diff options
Diffstat (limited to 'vendor/gimli/src')
42 files changed, 0 insertions, 47171 deletions
diff --git a/vendor/gimli/src/arch.rs b/vendor/gimli/src/arch.rs deleted file mode 100644 index af5d4ba..0000000 --- a/vendor/gimli/src/arch.rs +++ /dev/null @@ -1,839 +0,0 @@ -use crate::common::Register; - -macro_rules! registers { - ($struct_name:ident, { $($name:ident = ($val:expr, $disp:expr)),+ $(,)? } - $(, aliases { $($alias_name:ident = ($alias_val:expr, $alias_disp:expr)),+ $(,)? })?) => { - #[allow(missing_docs)] - impl $struct_name { - $( - pub const $name: Register = Register($val); - )+ - $( - $(pub const $alias_name: Register = Register($alias_val);)+ - )* - } - - impl $struct_name { - /// The name of a register, or `None` if the register number is unknown. - /// - /// Only returns the primary name for registers that alias with others. - pub fn register_name(register: Register) -> Option<&'static str> { - match register { - $( - Self::$name => Some($disp), - )+ - _ => return None, - } - } - - /// Converts a register name into a register number. - pub fn name_to_register(value: &str) -> Option<Register> { - match value { - $( - $disp => Some(Self::$name), - )+ - $( - $($alias_disp => Some(Self::$alias_name),)+ - )* - _ => return None, - } - } - } - }; -} - -/// ARM architecture specific definitions. -/// -/// See [DWARF for the ARM Architecture]( -/// https://github.com/ARM-software/abi-aa/blob/main/aadwarf32/aadwarf32.rst). -#[derive(Debug, Clone, Copy)] -pub struct Arm; - -registers!(Arm, { - R0 = (0, "R0"), - R1 = (1, "R1"), - R2 = (2, "R2"), - R3 = (3, "R3"), - R4 = (4, "R4"), - R5 = (5, "R5"), - R6 = (6, "R6"), - R7 = (7, "R7"), - R8 = (8, "R8"), - R9 = (9, "R9"), - R10 = (10, "R10"), - R11 = (11, "R11"), - R12 = (12, "R12"), - R13 = (13, "R13"), - R14 = (14, "R14"), - R15 = (15, "R15"), - - WCGR0 = (104, "wCGR0"), - WCGR1 = (105, "wCGR1"), - WCGR2 = (106, "wCGR2"), - WCGR3 = (107, "wCGR3"), - WCGR4 = (108, "wCGR4"), - WCGR5 = (109, "wCGR5"), - WCGR6 = (110, "wCGR6"), - WCGR7 = (111, "wCGR7"), - - WR0 = (112, "wR0"), - WR1 = (113, "wR1"), - WR2 = (114, "wR2"), - WR3 = (115, "wR3"), - WR4 = (116, "wR4"), - WR5 = (117, "wR5"), - WR6 = (118, "wR6"), - WR7 = (119, "wR7"), - WR8 = (120, "wR8"), - WR9 = (121, "wR9"), - WR10 = (122, "wR10"), - WR11 = (123, "wR11"), - WR12 = (124, "wR12"), - WR13 = (125, "wR13"), - WR14 = (126, "wR14"), - WR15 = (127, "wR15"), - - SPSR = (128, "SPSR"), - SPSR_FIQ = (129, "SPSR_FIQ"), - SPSR_IRQ = (130, "SPSR_IRQ"), - SPSR_ABT = (131, "SPSR_ABT"), - SPSR_UND = (132, "SPSR_UND"), - SPSR_SVC = (133, "SPSR_SVC"), - - RA_AUTH_CODE = (143, "RA_AUTH_CODE"), - - R8_USR = (144, "R8_USR"), - R9_USR = (145, "R9_USR"), - R10_USR = (146, "R10_USR"), - R11_USR = (147, "R11_USR"), - R12_USR = (148, "R12_USR"), - R13_USR = (149, "R13_USR"), - R14_USR = (150, "R14_USR"), - - R8_FIQ = (151, "R8_FIQ"), - R9_FIQ = (152, "R9_FIQ"), - R10_FIQ = (153, "R10_FIQ"), - R11_FIQ = (154, "R11_FIQ"), - R12_FIQ = (155, "R12_FIQ"), - R13_FIQ = (156, "R13_FIQ"), - R14_FIQ = (157, "R14_FIQ"), - - R13_IRQ = (158, "R13_IRQ"), - R14_IRQ = (159, "R14_IRQ"), - - R13_ABT = (160, "R13_ABT"), - R14_ABT = (161, "R14_ABT"), - - R13_UND = (162, "R13_UND"), - R14_UND = (163, "R14_UND"), - - R13_SVC = (164, "R13_SVC"), - R14_SVC = (165, "R14_SVC"), - - WC0 = (192, "wC0"), - WC1 = (193, "wC1"), - WC2 = (194, "wC2"), - WC3 = (195, "wC3"), - WC4 = (196, "wC4"), - WC5 = (197, "wC5"), - WC6 = (198, "wC6"), - WC7 = (199, "wC7"), - - D0 = (256, "D0"), - D1 = (257, "D1"), - D2 = (258, "D2"), - D3 = (259, "D3"), - D4 = (260, "D4"), - D5 = (261, "D5"), - D6 = (262, "D6"), - D7 = (263, "D7"), - D8 = (264, "D8"), - D9 = (265, "D9"), - D10 = (266, "D10"), - D11 = (267, "D11"), - D12 = (268, "D12"), - D13 = (269, "D13"), - D14 = (270, "D14"), - D15 = (271, "D15"), - D16 = (272, "D16"), - D17 = (273, "D17"), - D18 = (274, "D18"), - D19 = (275, "D19"), - D20 = (276, "D20"), - D21 = (277, "D21"), - D22 = (278, "D22"), - D23 = (279, "D23"), - D24 = (280, "D24"), - D25 = (281, "D25"), - D26 = (282, "D26"), - D27 = (283, "D27"), - D28 = (284, "D28"), - D29 = (285, "D29"), - D30 = (286, "D30"), - D31 = (287, "D31"), - - TPIDRURO = (320, "TPIDRURO"), - TPIDRURW = (321, "TPIDRURW"), - TPIDPR = (322, "TPIDPR"), - HTPIDPR = (323, "HTPIDPR"), -}, -aliases { - SP = (13, "SP"), - LR = (14, "LR"), - PC = (15, "PC"), - - ACC0 = (104, "ACC0"), - ACC1 = (105, "ACC1"), - ACC2 = (106, "ACC2"), - ACC3 = (107, "ACC3"), - ACC4 = (108, "ACC4"), - ACC5 = (109, "ACC5"), - ACC6 = (110, "ACC6"), - ACC7 = (111, "ACC7"), - - S0 = (256, "S0"), - S1 = (256, "S1"), - S2 = (257, "S2"), - S3 = (257, "S3"), - S4 = (258, "S4"), - S5 = (258, "S5"), - S6 = (259, "S6"), - S7 = (259, "S7"), - S8 = (260, "S8"), - S9 = (260, "S9"), - S10 = (261, "S10"), - S11 = (261, "S11"), - S12 = (262, "S12"), - S13 = (262, "S13"), - S14 = (263, "S14"), - S15 = (263, "S15"), - S16 = (264, "S16"), - S17 = (264, "S17"), - S18 = (265, "S18"), - S19 = (265, "S19"), - S20 = (266, "S20"), - S21 = (266, "S21"), - S22 = (267, "S22"), - S23 = (267, "S23"), - S24 = (268, "S24"), - S25 = (268, "S25"), - S26 = (269, "S26"), - S27 = (269, "S27"), - S28 = (270, "S28"), - S29 = (270, "S29"), - S30 = (271, "S30"), - S31 = (271, "S31"), -}); - -/// ARM 64-bit (AArch64) architecture specific definitions. -/// -/// See [DWARF for the ARM 64-bit Architecture]( -/// https://github.com/ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst). -#[derive(Debug, Clone, Copy)] -pub struct AArch64; - -registers!(AArch64, { - X0 = (0, "X0"), - X1 = (1, "X1"), - X2 = (2, "X2"), - X3 = (3, "X3"), - X4 = (4, "X4"), - X5 = (5, "X5"), - X6 = (6, "X6"), - X7 = (7, "X7"), - X8 = (8, "X8"), - X9 = (9, "X9"), - X10 = (10, "X10"), - X11 = (11, "X11"), - X12 = (12, "X12"), - X13 = (13, "X13"), - X14 = (14, "X14"), - X15 = (15, "X15"), - X16 = (16, "X16"), - X17 = (17, "X17"), - X18 = (18, "X18"), - X19 = (19, "X19"), - X20 = (20, "X20"), - X21 = (21, "X21"), - X22 = (22, "X22"), - X23 = (23, "X23"), - X24 = (24, "X24"), - X25 = (25, "X25"), - X26 = (26, "X26"), - X27 = (27, "X27"), - X28 = (28, "X28"), - X29 = (29, "X29"), - X30 = (30, "X30"), - SP = (31, "SP"), - PC = (32, "PC"), - ELR_MODE = (33, "ELR_mode"), - RA_SIGN_STATE = (34, "RA_SIGN_STATE"), - TPIDRRO_EL0 = (35, "TPIDRRO_EL0"), - TPIDR_EL0 = (36, "TPIDR_EL0"), - TPIDR_EL1 = (37, "TPIDR_EL1"), - TPIDR_EL2 = (38, "TPIDR_EL2"), - TPIDR_EL3 = (39, "TPIDR_EL3"), - - VG = (46, "VG"), - FFR = (47, "FFR"), - - P0 = (48, "P0"), - P1 = (49, "P1"), - P2 = (50, "P2"), - P3 = (51, "P3"), - P4 = (52, "P4"), - P5 = (53, "P5"), - P6 = (54, "P6"), - P7 = (55, "P7"), - P8 = (56, "P8"), - P9 = (57, "P9"), - P10 = (58, "P10"), - P11 = (59, "P11"), - P12 = (60, "P12"), - P13 = (61, "P13"), - P14 = (62, "P14"), - P15 = (63, "P15"), - - V0 = (64, "V0"), - V1 = (65, "V1"), - V2 = (66, "V2"), - V3 = (67, "V3"), - V4 = (68, "V4"), - V5 = (69, "V5"), - V6 = (70, "V6"), - V7 = (71, "V7"), - V8 = (72, "V8"), - V9 = (73, "V9"), - V10 = (74, "V10"), - V11 = (75, "V11"), - V12 = (76, "V12"), - V13 = (77, "V13"), - V14 = (78, "V14"), - V15 = (79, "V15"), - V16 = (80, "V16"), - V17 = (81, "V17"), - V18 = (82, "V18"), - V19 = (83, "V19"), - V20 = (84, "V20"), - V21 = (85, "V21"), - V22 = (86, "V22"), - V23 = (87, "V23"), - V24 = (88, "V24"), - V25 = (89, "V25"), - V26 = (90, "V26"), - V27 = (91, "V27"), - V28 = (92, "V28"), - V29 = (93, "V29"), - V30 = (94, "V30"), - V31 = (95, "V31"), - - Z0 = (96, "Z0"), - Z1 = (97, "Z1"), - Z2 = (98, "Z2"), - Z3 = (99, "Z3"), - Z4 = (100, "Z4"), - Z5 = (101, "Z5"), - Z6 = (102, "Z6"), - Z7 = (103, "Z7"), - Z8 = (104, "Z8"), - Z9 = (105, "Z9"), - Z10 = (106, "Z10"), - Z11 = (107, "Z11"), - Z12 = (108, "Z12"), - Z13 = (109, "Z13"), - Z14 = (110, "Z14"), - Z15 = (111, "Z15"), - Z16 = (112, "Z16"), - Z17 = (113, "Z17"), - Z18 = (114, "Z18"), - Z19 = (115, "Z19"), - Z20 = (116, "Z20"), - Z21 = (117, "Z21"), - Z22 = (118, "Z22"), - Z23 = (119, "Z23"), - Z24 = (120, "Z24"), - Z25 = (121, "Z25"), - Z26 = (122, "Z26"), - Z27 = (123, "Z27"), - Z28 = (124, "Z28"), - Z29 = (125, "Z29"), - Z30 = (126, "Z30"), - Z31 = (127, "Z31"), -}); - -/// LoongArch architecture specific definitions. -/// -/// See [LoongArch ELF psABI specification](https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html). -#[derive(Debug, Clone, Copy)] -pub struct LoongArch; - -registers!(LoongArch, { - R0 = (0, "$r0"), - R1 = (1, "$r1"), - R2 = (2, "$r2"), - R3 = (3, "$r3"), - R4 = (4, "$r4"), - R5 = (5, "$r5"), - R6 = (6, "$r6"), - R7 = (7, "$r7"), - R8 = (8, "$r8"), - R9 = (9, "$r9"), - R10 = (10, "$r10"), - R11 = (11, "$r11"), - R12 = (12, "$r12"), - R13 = (13, "$r13"), - R14 = (14, "$r14"), - R15 = (15, "$r15"), - R16 = (16, "$r16"), - R17 = (17, "$r17"), - R18 = (18, "$r18"), - R19 = (19, "$r19"), - R20 = (20, "$r20"), - R21 = (21, "$r21"), - R22 = (22, "$r22"), - R23 = (23, "$r23"), - R24 = (24, "$r24"), - R25 = (25, "$r25"), - R26 = (26, "$r26"), - R27 = (27, "$r27"), - R28 = (28, "$r28"), - R29 = (29, "$r29"), - R30 = (30, "$r30"), - R31 = (31, "$r31"), - - F0 = (32, "$f0"), - F1 = (33, "$f1"), - F2 = (34, "$f2"), - F3 = (35, "$f3"), - F4 = (36, "$f4"), - F5 = (37, "$f5"), - F6 = (38, "$f6"), - F7 = (39, "$f7"), - F8 = (40, "$f8"), - F9 = (41, "$f9"), - F10 = (42, "$f10"), - F11 = (43, "$f11"), - F12 = (44, "$f12"), - F13 = (45, "$f13"), - F14 = (46, "$f14"), - F15 = (47, "$f15"), - F16 = (48, "$f16"), - F17 = (49, "$f17"), - F18 = (50, "$f18"), - F19 = (51, "$f19"), - F20 = (52, "$f20"), - F21 = (53, "$f21"), - F22 = (54, "$f22"), - F23 = (55, "$f23"), - F24 = (56, "$f24"), - F25 = (57, "$f25"), - F26 = (58, "$f26"), - F27 = (59, "$f27"), - F28 = (60, "$f28"), - F29 = (61, "$f29"), - F30 = (62, "$f30"), - F31 = (63, "$f31"), - FCC0 = (64, "$fcc0"), - FCC1 = (65, "$fcc1"), - FCC2 = (66, "$fcc2"), - FCC3 = (67, "$fcc3"), - FCC4 = (68, "$fcc4"), - FCC5 = (69, "$fcc5"), - FCC6 = (70, "$fcc6"), - FCC7 = (71, "$fcc7"), -}, -aliases { - ZERO = (0, "$zero"), - RA = (1, "$ra"), - TP = (2, "$tp"), - SP = (3, "$sp"), - A0 = (4, "$a0"), - A1 = (5, "$a1"), - A2 = (6, "$a2"), - A3 = (7, "$a3"), - A4 = (8, "$a4"), - A5 = (9, "$a5"), - A6 = (10, "$a6"), - A7 = (11, "$a7"), - T0 = (12, "$t0"), - T1 = (13, "$t1"), - T2 = (14, "$t2"), - T3 = (15, "$t3"), - T4 = (16, "$t4"), - T5 = (17, "$t5"), - T6 = (18, "$t6"), - T7 = (19, "$t7"), - T8 = (20, "$t8"), - FP = (22, "$fp"), - S0 = (23, "$s0"), - S1 = (24, "$s1"), - S2 = (25, "$s2"), - S3 = (26, "$s3"), - S4 = (27, "$s4"), - S5 = (28, "$s5"), - S6 = (29, "$s6"), - S7 = (30, "$s7"), - S8 = (31, "$s8"), - - FA0 = (32, "$fa0"), - FA1 = (33, "$fa1"), - FA2 = (34, "$fa2"), - FA3 = (35, "$fa3"), - FA4 = (36, "$fa4"), - FA5 = (37, "$fa5"), - FA6 = (38, "$fa6"), - FA7 = (39, "$fa7"), - FT0 = (40, "$ft0"), - FT1 = (41, "$ft1"), - FT2 = (42, "$ft2"), - FT3 = (43, "$ft3"), - FT4 = (44, "$ft4"), - FT5 = (45, "$ft5"), - FT6 = (46, "$ft6"), - FT7 = (47, "$ft7"), - FT8 = (48, "$ft8"), - FT9 = (49, "$ft9"), - FT10 = (50, "$ft10"), - FT11 = (51, "$ft11"), - FT12 = (52, "$ft12"), - FT13 = (53, "$ft13"), - FT14 = (54, "$ft14"), - FT15 = (55, "$ft15"), - FS0 = (56, "$fs0"), - FS1 = (57, "$fs1"), - FS2 = (58, "$fs2"), - FS3 = (59, "$fs3"), - FS4 = (60, "$fs4"), - FS5 = (61, "$fs5"), - FS6 = (62, "$fs6"), - FS7 = (63, "$fs7"), -}); - -/// RISC-V architecture specific definitions. -/// -/// See [RISC-V ELF psABI specification](https://github.com/riscv/riscv-elf-psabi-doc). -#[derive(Debug, Clone, Copy)] -pub struct RiscV; - -registers!(RiscV, { - X0 = (0, "x0"), - X1 = (1, "x1"), - X2 = (2, "x2"), - X3 = (3, "x3"), - X4 = (4, "x4"), - X5 = (5, "x5"), - X6 = (6, "x6"), - X7 = (7, "x7"), - X8 = (8, "x8"), - X9 = (9, "x9"), - X10 = (10, "x10"), - X11 = (11, "x11"), - X12 = (12, "x12"), - X13 = (13, "x13"), - X14 = (14, "x14"), - X15 = (15, "x15"), - X16 = (16, "x16"), - X17 = (17, "x17"), - X18 = (18, "x18"), - X19 = (19, "x19"), - X20 = (20, "x20"), - X21 = (21, "x21"), - X22 = (22, "x22"), - X23 = (23, "x23"), - X24 = (24, "x24"), - X25 = (25, "x25"), - X26 = (26, "x26"), - X27 = (27, "x27"), - X28 = (28, "x28"), - X29 = (29, "x29"), - X30 = (30, "x30"), - X31 = (31, "x31"), - - F0 = (32, "f0"), - F1 = (33, "f1"), - F2 = (34, "f2"), - F3 = (35, "f3"), - F4 = (36, "f4"), - F5 = (37, "f5"), - F6 = (38, "f6"), - F7 = (39, "f7"), - F8 = (40, "f8"), - F9 = (41, "f9"), - F10 = (42, "f10"), - F11 = (43, "f11"), - F12 = (44, "f12"), - F13 = (45, "f13"), - F14 = (46, "f14"), - F15 = (47, "f15"), - F16 = (48, "f16"), - F17 = (49, "f17"), - F18 = (50, "f18"), - F19 = (51, "f19"), - F20 = (52, "f20"), - F21 = (53, "f21"), - F22 = (54, "f22"), - F23 = (55, "f23"), - F24 = (56, "f24"), - F25 = (57, "f25"), - F26 = (58, "f26"), - F27 = (59, "f27"), - F28 = (60, "f28"), - F29 = (61, "f29"), - F30 = (62, "f30"), - F31 = (63, "f31"), -}, -aliases { - ZERO = (0, "zero"), - RA = (1, "ra"), - SP = (2, "sp"), - GP = (3, "gp"), - TP = (4, "tp"), - T0 = (5, "t0"), - T1 = (6, "t1"), - T2 = (7, "t2"), - S0 = (8, "s0"), - S1 = (9, "s1"), - A0 = (10, "a0"), - A1 = (11, "a1"), - A2 = (12, "a2"), - A3 = (13, "a3"), - A4 = (14, "a4"), - A5 = (15, "a5"), - A6 = (16, "a6"), - A7 = (17, "a7"), - S2 = (18, "s2"), - S3 = (19, "s3"), - S4 = (20, "s4"), - S5 = (21, "s5"), - S6 = (22, "s6"), - S7 = (23, "s7"), - S8 = (24, "s8"), - S9 = (25, "s9"), - S10 = (26, "s10"), - S11 = (27, "s11"), - T3 = (28, "t3"), - T4 = (29, "t4"), - T5 = (30, "t5"), - T6 = (31, "t6"), - - FT0 = (32, "ft0"), - FT1 = (33, "ft1"), - FT2 = (34, "ft2"), - FT3 = (35, "ft3"), - FT4 = (36, "ft4"), - FT5 = (37, "ft5"), - FT6 = (38, "ft6"), - FT7 = (39, "ft7"), - FS0 = (40, "fs0"), - FS1 = (41, "fs1"), - FA0 = (42, "fa0"), - FA1 = (43, "fa1"), - FA2 = (44, "fa2"), - FA3 = (45, "fa3"), - FA4 = (46, "fa4"), - FA5 = (47, "fa5"), - FA6 = (48, "fa6"), - FA7 = (49, "fa7"), - FS2 = (50, "fs2"), - FS3 = (51, "fs3"), - FS4 = (52, "fs4"), - FS5 = (53, "fs5"), - FS6 = (54, "fs6"), - FS7 = (55, "fs7"), - FS8 = (56, "fs8"), - FS9 = (57, "fs9"), - FS10 = (58, "fs10"), - FS11 = (59, "fs11"), - FT8 = (60, "ft8"), - FT9 = (61, "ft9"), - FT10 = (62, "ft10"), - FT11 = (63, "ft11"), -}); - -/// Intel i386 architecture specific definitions. -/// -/// See Intel386 psABi version 1.1 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI). -#[derive(Debug, Clone, Copy)] -pub struct X86; - -registers!(X86, { - EAX = (0, "eax"), - ECX = (1, "ecx"), - EDX = (2, "edx"), - EBX = (3, "ebx"), - ESP = (4, "esp"), - EBP = (5, "ebp"), - ESI = (6, "esi"), - EDI = (7, "edi"), - - // Return Address register. This is stored in `0(%esp, "")` and is not a physical register. - RA = (8, "RA"), - - ST0 = (11, "st0"), - ST1 = (12, "st1"), - ST2 = (13, "st2"), - ST3 = (14, "st3"), - ST4 = (15, "st4"), - ST5 = (16, "st5"), - ST6 = (17, "st6"), - ST7 = (18, "st7"), - - XMM0 = (21, "xmm0"), - XMM1 = (22, "xmm1"), - XMM2 = (23, "xmm2"), - XMM3 = (24, "xmm3"), - XMM4 = (25, "xmm4"), - XMM5 = (26, "xmm5"), - XMM6 = (27, "xmm6"), - XMM7 = (28, "xmm7"), - - MM0 = (29, "mm0"), - MM1 = (30, "mm1"), - MM2 = (31, "mm2"), - MM3 = (32, "mm3"), - MM4 = (33, "mm4"), - MM5 = (34, "mm5"), - MM6 = (35, "mm6"), - MM7 = (36, "mm7"), - - MXCSR = (39, "mxcsr"), - - ES = (40, "es"), - CS = (41, "cs"), - SS = (42, "ss"), - DS = (43, "ds"), - FS = (44, "fs"), - GS = (45, "gs"), - - TR = (48, "tr"), - LDTR = (49, "ldtr"), - - FS_BASE = (93, "fs.base"), - GS_BASE = (94, "gs.base"), -}); - -/// AMD64 architecture specific definitions. -/// -/// See x86-64 psABI version 1.0 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI). -#[derive(Debug, Clone, Copy)] -pub struct X86_64; - -registers!(X86_64, { - RAX = (0, "rax"), - RDX = (1, "rdx"), - RCX = (2, "rcx"), - RBX = (3, "rbx"), - RSI = (4, "rsi"), - RDI = (5, "rdi"), - RBP = (6, "rbp"), - RSP = (7, "rsp"), - - R8 = (8, "r8"), - R9 = (9, "r9"), - R10 = (10, "r10"), - R11 = (11, "r11"), - R12 = (12, "r12"), - R13 = (13, "r13"), - R14 = (14, "r14"), - R15 = (15, "r15"), - - // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register. - RA = (16, "RA"), - - XMM0 = (17, "xmm0"), - XMM1 = (18, "xmm1"), - XMM2 = (19, "xmm2"), - XMM3 = (20, "xmm3"), - XMM4 = (21, "xmm4"), - XMM5 = (22, "xmm5"), - XMM6 = (23, "xmm6"), - XMM7 = (24, "xmm7"), - - XMM8 = (25, "xmm8"), - XMM9 = (26, "xmm9"), - XMM10 = (27, "xmm10"), - XMM11 = (28, "xmm11"), - XMM12 = (29, "xmm12"), - XMM13 = (30, "xmm13"), - XMM14 = (31, "xmm14"), - XMM15 = (32, "xmm15"), - - ST0 = (33, "st0"), - ST1 = (34, "st1"), - ST2 = (35, "st2"), - ST3 = (36, "st3"), - ST4 = (37, "st4"), - ST5 = (38, "st5"), - ST6 = (39, "st6"), - ST7 = (40, "st7"), - - MM0 = (41, "mm0"), - MM1 = (42, "mm1"), - MM2 = (43, "mm2"), - MM3 = (44, "mm3"), - MM4 = (45, "mm4"), - MM5 = (46, "mm5"), - MM6 = (47, "mm6"), - MM7 = (48, "mm7"), - - RFLAGS = (49, "rFLAGS"), - ES = (50, "es"), - CS = (51, "cs"), - SS = (52, "ss"), - DS = (53, "ds"), - FS = (54, "fs"), - GS = (55, "gs"), - - FS_BASE = (58, "fs.base"), - GS_BASE = (59, "gs.base"), - - TR = (62, "tr"), - LDTR = (63, "ldtr"), - MXCSR = (64, "mxcsr"), - FCW = (65, "fcw"), - FSW = (66, "fsw"), - - XMM16 = (67, "xmm16"), - XMM17 = (68, "xmm17"), - XMM18 = (69, "xmm18"), - XMM19 = (70, "xmm19"), - XMM20 = (71, "xmm20"), - XMM21 = (72, "xmm21"), - XMM22 = (73, "xmm22"), - XMM23 = (74, "xmm23"), - XMM24 = (75, "xmm24"), - XMM25 = (76, "xmm25"), - XMM26 = (77, "xmm26"), - XMM27 = (78, "xmm27"), - XMM28 = (79, "xmm28"), - XMM29 = (80, "xmm29"), - XMM30 = (81, "xmm30"), - XMM31 = (82, "xmm31"), - - K0 = (118, "k0"), - K1 = (119, "k1"), - K2 = (120, "k2"), - K3 = (121, "k3"), - K4 = (122, "k4"), - K5 = (123, "k5"), - K6 = (124, "k6"), - K7 = (125, "k7"), -}); - -#[cfg(test)] -mod tests { - - #[test] - #[cfg(feature = "std")] - fn test_aarch64_registers() { - use super::*; - use std::collections::HashSet; - - let mut names = HashSet::new(); - for n in (0..=39).chain(46..=127) { - let name = AArch64::register_name(Register(n)) - .unwrap_or_else(|| panic!("Register {} should have a name.", n)); - assert!(names.insert(name)); - } - } -} diff --git a/vendor/gimli/src/common.rs b/vendor/gimli/src/common.rs deleted file mode 100644 index fc6693d..0000000 --- a/vendor/gimli/src/common.rs +++ /dev/null @@ -1,391 +0,0 @@ -/// Whether the format of a compilation unit is 32- or 64-bit. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Format { - /// 64-bit DWARF - Dwarf64 = 8, - /// 32-bit DWARF - Dwarf32 = 4, -} - -impl Format { - /// Return the serialized size of an initial length field for the format. - #[inline] - pub fn initial_length_size(self) -> u8 { - match self { - Format::Dwarf32 => 4, - Format::Dwarf64 => 12, - } - } - - /// Return the natural word size for the format - #[inline] - pub fn word_size(self) -> u8 { - match self { - Format::Dwarf32 => 4, - Format::Dwarf64 => 8, - } - } -} - -/// Which vendor extensions to support. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[non_exhaustive] -pub enum Vendor { - /// A default set of extensions, including some common GNU extensions. - Default, - /// AAarch64 extensions. - AArch64, -} - -/// Encoding parameters that are commonly used for multiple DWARF sections. -/// -/// This is intended to be small enough to pass by value. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -// `address_size` and `format` are used more often than `version`, so keep -// them first. -#[repr(C)] -pub struct Encoding { - /// The size of an address. - pub address_size: u8, - - // The size of a segment selector. - // TODO: pub segment_size: u8, - /// Whether the DWARF format is 32- or 64-bit. - pub format: Format, - - /// The DWARF version of the header. - pub version: u16, -} - -/// Encoding parameters for a line number program. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct LineEncoding { - /// The size in bytes of the smallest target machine instruction. - pub minimum_instruction_length: u8, - - /// The maximum number of individual operations that may be encoded in an - /// instruction. - pub maximum_operations_per_instruction: u8, - - /// The initial value of the `is_stmt` register. - pub default_is_stmt: bool, - - /// The minimum value which a special opcode can add to the line register. - pub line_base: i8, - - /// The range of values which a special opcode can add to the line register. - pub line_range: u8, -} - -impl Default for LineEncoding { - fn default() -> Self { - // Values from LLVM. - LineEncoding { - minimum_instruction_length: 1, - maximum_operations_per_instruction: 1, - default_is_stmt: true, - line_base: -5, - line_range: 14, - } - } -} - -/// A DWARF register number. -/// -/// The meaning of this value is ABI dependent. This is generally encoded as -/// a ULEB128, but supported architectures need 16 bits at most. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Register(pub u16); - -/// An offset into the `.debug_abbrev` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DebugAbbrevOffset<T = usize>(pub T); - -/// An offset to a set of entries in the `.debug_addr` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugAddrBase<T = usize>(pub T); - -/// An index into a set of addresses in the `.debug_addr` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugAddrIndex<T = usize>(pub T); - -/// An offset into the `.debug_aranges` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugArangesOffset<T = usize>(pub T); - -/// An offset into the `.debug_info` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] -pub struct DebugInfoOffset<T = usize>(pub T); - -/// An offset into the `.debug_line` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugLineOffset<T = usize>(pub T); - -/// An offset into the `.debug_line_str` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugLineStrOffset<T = usize>(pub T); - -/// An offset into either the `.debug_loc` section or the `.debug_loclists` section, -/// depending on the version of the unit the offset was contained in. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct LocationListsOffset<T = usize>(pub T); - -/// An offset to a set of location list offsets in the `.debug_loclists` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugLocListsBase<T = usize>(pub T); - -/// An index into a set of location list offsets in the `.debug_loclists` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugLocListsIndex<T = usize>(pub T); - -/// An offset into the `.debug_macinfo` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DebugMacinfoOffset<T = usize>(pub T); - -/// An offset into the `.debug_macro` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DebugMacroOffset<T = usize>(pub T); - -/// An offset into either the `.debug_ranges` section or the `.debug_rnglists` section, -/// depending on the version of the unit the offset was contained in. -/// -/// If this is from a DWARF 4 DWO file, then it must additionally be offset by the -/// value of `DW_AT_GNU_ranges_base`. You can use `Dwarf::ranges_offset_from_raw` to do this. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct RawRangeListsOffset<T = usize>(pub T); - -/// An offset into either the `.debug_ranges` section or the `.debug_rnglists` section, -/// depending on the version of the unit the offset was contained in. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct RangeListsOffset<T = usize>(pub T); - -/// An offset to a set of range list offsets in the `.debug_rnglists` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugRngListsBase<T = usize>(pub T); - -/// An index into a set of range list offsets in the `.debug_rnglists` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugRngListsIndex<T = usize>(pub T); - -/// An offset into the `.debug_str` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugStrOffset<T = usize>(pub T); - -/// An offset to a set of entries in the `.debug_str_offsets` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugStrOffsetsBase<T = usize>(pub T); - -/// An index into a set of entries in the `.debug_str_offsets` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct DebugStrOffsetsIndex<T = usize>(pub T); - -/// An offset into the `.debug_types` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] -pub struct DebugTypesOffset<T = usize>(pub T); - -/// A type signature as used in the `.debug_types` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DebugTypeSignature(pub u64); - -/// An offset into the `.debug_frame` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DebugFrameOffset<T = usize>(pub T); - -impl<T> From<T> for DebugFrameOffset<T> { - #[inline] - fn from(o: T) -> Self { - DebugFrameOffset(o) - } -} - -/// An offset into the `.eh_frame` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct EhFrameOffset<T = usize>(pub T); - -impl<T> From<T> for EhFrameOffset<T> { - #[inline] - fn from(o: T) -> Self { - EhFrameOffset(o) - } -} - -/// An offset into the `.debug_info` or `.debug_types` sections. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] -pub enum UnitSectionOffset<T = usize> { - /// An offset into the `.debug_info` section. - DebugInfoOffset(DebugInfoOffset<T>), - /// An offset into the `.debug_types` section. - DebugTypesOffset(DebugTypesOffset<T>), -} - -impl<T> From<DebugInfoOffset<T>> for UnitSectionOffset<T> { - fn from(offset: DebugInfoOffset<T>) -> Self { - UnitSectionOffset::DebugInfoOffset(offset) - } -} - -impl<T> From<DebugTypesOffset<T>> for UnitSectionOffset<T> { - fn from(offset: DebugTypesOffset<T>) -> Self { - UnitSectionOffset::DebugTypesOffset(offset) - } -} - -impl<T> UnitSectionOffset<T> -where - T: Clone, -{ - /// Returns the `DebugInfoOffset` inside, or `None` otherwise. - pub fn as_debug_info_offset(&self) -> Option<DebugInfoOffset<T>> { - match self { - UnitSectionOffset::DebugInfoOffset(offset) => Some(offset.clone()), - UnitSectionOffset::DebugTypesOffset(_) => None, - } - } - /// Returns the `DebugTypesOffset` inside, or `None` otherwise. - pub fn as_debug_types_offset(&self) -> Option<DebugTypesOffset<T>> { - match self { - UnitSectionOffset::DebugInfoOffset(_) => None, - UnitSectionOffset::DebugTypesOffset(offset) => Some(offset.clone()), - } - } -} - -/// An identifier for a DWARF section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] -pub enum SectionId { - /// The `.debug_abbrev` section. - DebugAbbrev, - /// The `.debug_addr` section. - DebugAddr, - /// The `.debug_aranges` section. - DebugAranges, - /// The `.debug_cu_index` section. - DebugCuIndex, - /// The `.debug_frame` section. - DebugFrame, - /// The `.eh_frame` section. - EhFrame, - /// The `.eh_frame_hdr` section. - EhFrameHdr, - /// The `.debug_info` section. - DebugInfo, - /// The `.debug_line` section. - DebugLine, - /// The `.debug_line_str` section. - DebugLineStr, - /// The `.debug_loc` section. - DebugLoc, - /// The `.debug_loclists` section. - DebugLocLists, - /// The `.debug_macinfo` section. - DebugMacinfo, - /// The `.debug_macro` section. - DebugMacro, - /// The `.debug_pubnames` section. - DebugPubNames, - /// The `.debug_pubtypes` section. - DebugPubTypes, - /// The `.debug_ranges` section. - DebugRanges, - /// The `.debug_rnglists` section. - DebugRngLists, - /// The `.debug_str` section. - DebugStr, - /// The `.debug_str_offsets` section. - DebugStrOffsets, - /// The `.debug_tu_index` section. - DebugTuIndex, - /// The `.debug_types` section. - DebugTypes, -} - -impl SectionId { - /// Returns the ELF section name for this kind. - pub fn name(self) -> &'static str { - match self { - SectionId::DebugAbbrev => ".debug_abbrev", - SectionId::DebugAddr => ".debug_addr", - SectionId::DebugAranges => ".debug_aranges", - SectionId::DebugCuIndex => ".debug_cu_index", - SectionId::DebugFrame => ".debug_frame", - SectionId::EhFrame => ".eh_frame", - SectionId::EhFrameHdr => ".eh_frame_hdr", - SectionId::DebugInfo => ".debug_info", - SectionId::DebugLine => ".debug_line", - SectionId::DebugLineStr => ".debug_line_str", - SectionId::DebugLoc => ".debug_loc", - SectionId::DebugLocLists => ".debug_loclists", - SectionId::DebugMacinfo => ".debug_macinfo", - SectionId::DebugMacro => ".debug_macro", - SectionId::DebugPubNames => ".debug_pubnames", - SectionId::DebugPubTypes => ".debug_pubtypes", - SectionId::DebugRanges => ".debug_ranges", - SectionId::DebugRngLists => ".debug_rnglists", - SectionId::DebugStr => ".debug_str", - SectionId::DebugStrOffsets => ".debug_str_offsets", - SectionId::DebugTuIndex => ".debug_tu_index", - SectionId::DebugTypes => ".debug_types", - } - } - - /// Returns the ELF section name for this kind, when found in a .dwo or .dwp file. - pub fn dwo_name(self) -> Option<&'static str> { - Some(match self { - SectionId::DebugAbbrev => ".debug_abbrev.dwo", - SectionId::DebugCuIndex => ".debug_cu_index", - SectionId::DebugInfo => ".debug_info.dwo", - SectionId::DebugLine => ".debug_line.dwo", - // The debug_loc section can be present in the dwo when using the - // GNU split-dwarf extension to DWARF4. - SectionId::DebugLoc => ".debug_loc.dwo", - SectionId::DebugLocLists => ".debug_loclists.dwo", - SectionId::DebugMacro => ".debug_macro.dwo", - SectionId::DebugRngLists => ".debug_rnglists.dwo", - SectionId::DebugStr => ".debug_str.dwo", - SectionId::DebugStrOffsets => ".debug_str_offsets.dwo", - SectionId::DebugTuIndex => ".debug_tu_index", - SectionId::DebugTypes => ".debug_types.dwo", - _ => return None, - }) - } - - /// Returns the XCOFF section name for this kind. - pub fn xcoff_name(self) -> Option<&'static str> { - Some(match self { - SectionId::DebugAbbrev => ".dwabrev", - SectionId::DebugAranges => ".dwarnge", - SectionId::DebugFrame => ".dwframe", - SectionId::DebugInfo => ".dwinfo", - SectionId::DebugLine => ".dwline", - SectionId::DebugLoc => ".dwloc", - SectionId::DebugMacinfo => ".dwmac", - SectionId::DebugPubNames => ".dwpbnms", - SectionId::DebugPubTypes => ".dwpbtyp", - SectionId::DebugRanges => ".dwrnges", - SectionId::DebugStr => ".dwstr", - _ => return None, - }) - } -} - -/// An optionally-provided implementation-defined compilation unit ID to enable -/// split DWARF and linking a split compilation unit back together. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DwoId(pub u64); - -/// The "type" of file with DWARF debugging information. This determines, among other things, -/// which files DWARF sections should be loaded from. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DwarfFileType { - /// A normal executable or object file. - Main, - /// A .dwo split DWARF file. - Dwo, - // TODO: Supplementary files, .dwps? -} - -impl Default for DwarfFileType { - fn default() -> Self { - DwarfFileType::Main - } -} diff --git a/vendor/gimli/src/constants.rs b/vendor/gimli/src/constants.rs deleted file mode 100644 index e58050b..0000000 --- a/vendor/gimli/src/constants.rs +++ /dev/null @@ -1,1435 +0,0 @@ -// This file originally from https://github.com/philipc/rust-dwarf/ and -// distributed under either MIT or Apache 2.0 licenses. -// -// Copyright 2016 The rust-dwarf Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Constant definitions. -//! -//! The DWARF spec's `DW_AT_*` type is represented as `struct DwAt(u16)`, -//! `DW_FORM_*` as `DwForm(u16)`, etc. -//! -//! There are also exported const definitions for each constant. - -#![allow(non_upper_case_globals)] -#![allow(missing_docs)] - -use core::fmt; - -// The `dw!` macro turns this: -// -// dw!(DwFoo(u32) { -// DW_FOO_bar = 0, -// DW_FOO_baz = 1, -// DW_FOO_bang = 2, -// }); -// -// into this: -// -// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -// pub struct DwFoo(pub u32); -// -// pub const DW_FOO_bar: DwFoo = DwFoo(0); -// pub const DW_FOO_baz: DwFoo = DwFoo(1); -// pub const DW_FOO_bang: DwFoo = DwFoo(2); -// -// impl DwFoo { -// pub fn static_string(&self) -> Option<&'static str> { -// ... -// } -// } -// -// impl fmt::Display for DwFoo { -// fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -// ... -// } -// } -macro_rules! dw { - ($(#[$meta:meta])* $struct_name:ident($struct_type:ty) - { $($name:ident = $val:expr),+ $(,)? } - $(, aliases { $($alias_name:ident = $alias_val:expr),+ $(,)? })? - ) => { - $(#[$meta])* - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] - pub struct $struct_name(pub $struct_type); - - $( - pub const $name: $struct_name = $struct_name($val); - )+ - $($( - pub const $alias_name: $struct_name = $struct_name($alias_val); - )+)* - - impl $struct_name { - pub fn static_string(&self) -> Option<&'static str> { - Some(match *self { - $( - $name => stringify!($name), - )+ - _ => return None, - }) - } - } - - impl fmt::Display for $struct_name { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if let Some(s) = self.static_string() { - f.pad(s) - } else { - #[cfg(feature = "read")] - { - f.pad(&format!("Unknown {}: {}", stringify!($struct_name), self.0)) - } - #[cfg(not(feature = "read"))] - { - write!(f, "Unknown {}: {}", stringify!($struct_name), self.0) - } - } - } - } - }; -} - -dw!( -/// The section type field in a `.dwp` unit index. -/// -/// This is used for version 5 and later. -/// -/// See Section 7.3.5. -DwSect(u32) { - DW_SECT_INFO = 1, - DW_SECT_ABBREV = 3, - DW_SECT_LINE = 4, - DW_SECT_LOCLISTS = 5, - DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACRO = 7, - DW_SECT_RNGLISTS = 8, -}); - -dw!( -/// The section type field in a `.dwp` unit index with version 2. -DwSectV2(u32) { - DW_SECT_V2_INFO = 1, - DW_SECT_V2_TYPES = 2, - DW_SECT_V2_ABBREV = 3, - DW_SECT_V2_LINE = 4, - DW_SECT_V2_LOC = 5, - DW_SECT_V2_STR_OFFSETS = 6, - DW_SECT_V2_MACINFO = 7, - DW_SECT_V2_MACRO = 8, -}); - -dw!( -/// The unit type field in a unit header. -/// -/// See Section 7.5.1, Table 7.2. -DwUt(u8) { - DW_UT_compile = 0x01, - DW_UT_type = 0x02, - DW_UT_partial = 0x03, - DW_UT_skeleton = 0x04, - DW_UT_split_compile = 0x05, - DW_UT_split_type = 0x06, - DW_UT_lo_user = 0x80, - DW_UT_hi_user = 0xff, -}); - -dw!( -/// The opcode for a call frame instruction. -/// -/// Section 7.24: -/// > Call frame instructions are encoded in one or more bytes. The primary -/// > opcode is encoded in the high order two bits of the first byte (that is, -/// > opcode = byte >> 6). An operand or extended opcode may be encoded in the -/// > low order 6 bits. Additional operands are encoded in subsequent bytes. -DwCfa(u8) { - DW_CFA_advance_loc = 0x01 << 6, - DW_CFA_offset = 0x02 << 6, - DW_CFA_restore = 0x03 << 6, - DW_CFA_nop = 0, - DW_CFA_set_loc = 0x01, - DW_CFA_advance_loc1 = 0x02, - DW_CFA_advance_loc2 = 0x03, - DW_CFA_advance_loc4 = 0x04, - DW_CFA_offset_extended = 0x05, - DW_CFA_restore_extended = 0x06, - DW_CFA_undefined = 0x07, - DW_CFA_same_value = 0x08, - DW_CFA_register = 0x09, - DW_CFA_remember_state = 0x0a, - DW_CFA_restore_state = 0x0b, - DW_CFA_def_cfa = 0x0c, - DW_CFA_def_cfa_register = 0x0d, - DW_CFA_def_cfa_offset = 0x0e, - DW_CFA_def_cfa_expression = 0x0f, - DW_CFA_expression = 0x10, - DW_CFA_offset_extended_sf = 0x11, - DW_CFA_def_cfa_sf = 0x12, - DW_CFA_def_cfa_offset_sf = 0x13, - DW_CFA_val_offset = 0x14, - DW_CFA_val_offset_sf = 0x15, - DW_CFA_val_expression = 0x16, - - DW_CFA_lo_user = 0x1c, - DW_CFA_hi_user = 0x3f, - - DW_CFA_MIPS_advance_loc8 = 0x1d, - DW_CFA_GNU_window_save = 0x2d, - DW_CFA_GNU_args_size = 0x2e, - DW_CFA_GNU_negative_offset_extended = 0x2f, -}, -aliases { - DW_CFA_AARCH64_negate_ra_state = 0x2d, -}); - -dw!( -/// The child determination encodings for DIE attributes. -/// -/// See Section 7.5.3, Table 7.4. -DwChildren(u8) { - DW_CHILDREN_no = 0, - DW_CHILDREN_yes = 1, -}); - -dw!( -/// The tag encodings for DIE attributes. -/// -/// See Section 7.5.3, Table 7.3. -DwTag(u16) { - DW_TAG_null = 0x00, - - DW_TAG_array_type = 0x01, - DW_TAG_class_type = 0x02, - DW_TAG_entry_point = 0x03, - DW_TAG_enumeration_type = 0x04, - DW_TAG_formal_parameter = 0x05, - DW_TAG_imported_declaration = 0x08, - DW_TAG_label = 0x0a, - DW_TAG_lexical_block = 0x0b, - DW_TAG_member = 0x0d, - DW_TAG_pointer_type = 0x0f, - DW_TAG_reference_type = 0x10, - DW_TAG_compile_unit = 0x11, - DW_TAG_string_type = 0x12, - DW_TAG_structure_type = 0x13, - DW_TAG_subroutine_type = 0x15, - DW_TAG_typedef = 0x16, - DW_TAG_union_type = 0x17, - DW_TAG_unspecified_parameters = 0x18, - DW_TAG_variant = 0x19, - DW_TAG_common_block = 0x1a, - DW_TAG_common_inclusion = 0x1b, - DW_TAG_inheritance = 0x1c, - DW_TAG_inlined_subroutine = 0x1d, - DW_TAG_module = 0x1e, - DW_TAG_ptr_to_member_type = 0x1f, - DW_TAG_set_type = 0x20, - DW_TAG_subrange_type = 0x21, - DW_TAG_with_stmt = 0x22, - DW_TAG_access_declaration = 0x23, - DW_TAG_base_type = 0x24, - DW_TAG_catch_block = 0x25, - DW_TAG_const_type = 0x26, - DW_TAG_constant = 0x27, - DW_TAG_enumerator = 0x28, - DW_TAG_file_type = 0x29, - DW_TAG_friend = 0x2a, - DW_TAG_namelist = 0x2b, - DW_TAG_namelist_item = 0x2c, - DW_TAG_packed_type = 0x2d, - DW_TAG_subprogram = 0x2e, - DW_TAG_template_type_parameter = 0x2f, - DW_TAG_template_value_parameter = 0x30, - DW_TAG_thrown_type = 0x31, - DW_TAG_try_block = 0x32, - DW_TAG_variant_part = 0x33, - DW_TAG_variable = 0x34, - DW_TAG_volatile_type = 0x35, - -// DWARF 3. - DW_TAG_dwarf_procedure = 0x36, - DW_TAG_restrict_type = 0x37, - DW_TAG_interface_type = 0x38, - DW_TAG_namespace = 0x39, - DW_TAG_imported_module = 0x3a, - DW_TAG_unspecified_type = 0x3b, - DW_TAG_partial_unit = 0x3c, - DW_TAG_imported_unit = 0x3d, - DW_TAG_condition = 0x3f, - DW_TAG_shared_type = 0x40, - -// DWARF 4. - DW_TAG_type_unit = 0x41, - DW_TAG_rvalue_reference_type = 0x42, - DW_TAG_template_alias = 0x43, - -// DWARF 5. - DW_TAG_coarray_type = 0x44, - DW_TAG_generic_subrange = 0x45, - DW_TAG_dynamic_type = 0x46, - DW_TAG_atomic_type = 0x47, - DW_TAG_call_site = 0x48, - DW_TAG_call_site_parameter = 0x49, - DW_TAG_skeleton_unit = 0x4a, - DW_TAG_immutable_type = 0x4b, - - DW_TAG_lo_user = 0x4080, - DW_TAG_hi_user = 0xffff, - -// SGI/MIPS extensions. - DW_TAG_MIPS_loop = 0x4081, - -// HP extensions. - DW_TAG_HP_array_descriptor = 0x4090, - DW_TAG_HP_Bliss_field = 0x4091, - DW_TAG_HP_Bliss_field_set = 0x4092, - -// GNU extensions. - DW_TAG_format_label = 0x4101, - DW_TAG_function_template = 0x4102, - DW_TAG_class_template = 0x4103, - DW_TAG_GNU_BINCL = 0x4104, - DW_TAG_GNU_EINCL = 0x4105, - DW_TAG_GNU_template_template_param = 0x4106, - DW_TAG_GNU_template_parameter_pack = 0x4107, - DW_TAG_GNU_formal_parameter_pack = 0x4108, - DW_TAG_GNU_call_site = 0x4109, - DW_TAG_GNU_call_site_parameter = 0x410a, - - DW_TAG_APPLE_property = 0x4200, - -// SUN extensions. - DW_TAG_SUN_function_template = 0x4201, - DW_TAG_SUN_class_template = 0x4202, - DW_TAG_SUN_struct_template = 0x4203, - DW_TAG_SUN_union_template = 0x4204, - DW_TAG_SUN_indirect_inheritance = 0x4205, - DW_TAG_SUN_codeflags = 0x4206, - DW_TAG_SUN_memop_info = 0x4207, - DW_TAG_SUN_omp_child_func = 0x4208, - DW_TAG_SUN_rtti_descriptor = 0x4209, - DW_TAG_SUN_dtor_info = 0x420a, - DW_TAG_SUN_dtor = 0x420b, - DW_TAG_SUN_f90_interface = 0x420c, - DW_TAG_SUN_fortran_vax_structure = 0x420d, - -// ALTIUM extensions. - DW_TAG_ALTIUM_circ_type = 0x5101, - DW_TAG_ALTIUM_mwa_circ_type = 0x5102, - DW_TAG_ALTIUM_rev_carry_type = 0x5103, - DW_TAG_ALTIUM_rom = 0x5111, - -// Extensions for UPC. - DW_TAG_upc_shared_type = 0x8765, - DW_TAG_upc_strict_type = 0x8766, - DW_TAG_upc_relaxed_type = 0x8767, - -// PGI (STMicroelectronics) extensions. - DW_TAG_PGI_kanji_type = 0xa000, - DW_TAG_PGI_interface_block = 0xa020, - -// Borland extensions. - DW_TAG_BORLAND_property = 0xb000, - DW_TAG_BORLAND_Delphi_string = 0xb001, - DW_TAG_BORLAND_Delphi_dynamic_array = 0xb002, - DW_TAG_BORLAND_Delphi_set = 0xb003, - DW_TAG_BORLAND_Delphi_variant = 0xb004, -}); - -dw!( -/// The attribute encodings for DIE attributes. -/// -/// See Section 7.5.4, Table 7.5. -DwAt(u16) { - DW_AT_null = 0x00, - - DW_AT_sibling = 0x01, - DW_AT_location = 0x02, - DW_AT_name = 0x03, - DW_AT_ordering = 0x09, - DW_AT_byte_size = 0x0b, - DW_AT_bit_offset = 0x0c, - DW_AT_bit_size = 0x0d, - DW_AT_stmt_list = 0x10, - DW_AT_low_pc = 0x11, - DW_AT_high_pc = 0x12, - DW_AT_language = 0x13, - DW_AT_discr = 0x15, - DW_AT_discr_value = 0x16, - DW_AT_visibility = 0x17, - DW_AT_import = 0x18, - DW_AT_string_length = 0x19, - DW_AT_common_reference = 0x1a, - DW_AT_comp_dir = 0x1b, - DW_AT_const_value = 0x1c, - DW_AT_containing_type = 0x1d, - DW_AT_default_value = 0x1e, - DW_AT_inline = 0x20, - DW_AT_is_optional = 0x21, - DW_AT_lower_bound = 0x22, - DW_AT_producer = 0x25, - DW_AT_prototyped = 0x27, - DW_AT_return_addr = 0x2a, - DW_AT_start_scope = 0x2c, - DW_AT_bit_stride = 0x2e, - DW_AT_upper_bound = 0x2f, - DW_AT_abstract_origin = 0x31, - DW_AT_accessibility = 0x32, - DW_AT_address_class = 0x33, - DW_AT_artificial = 0x34, - DW_AT_base_types = 0x35, - DW_AT_calling_convention = 0x36, - DW_AT_count = 0x37, - DW_AT_data_member_location = 0x38, - DW_AT_decl_column = 0x39, - DW_AT_decl_file = 0x3a, - DW_AT_decl_line = 0x3b, - DW_AT_declaration = 0x3c, - DW_AT_discr_list = 0x3d, - DW_AT_encoding = 0x3e, - DW_AT_external = 0x3f, - DW_AT_frame_base = 0x40, - DW_AT_friend = 0x41, - DW_AT_identifier_case = 0x42, - DW_AT_macro_info = 0x43, - DW_AT_namelist_item = 0x44, - DW_AT_priority = 0x45, - DW_AT_segment = 0x46, - DW_AT_specification = 0x47, - DW_AT_static_link = 0x48, - DW_AT_type = 0x49, - DW_AT_use_location = 0x4a, - DW_AT_variable_parameter = 0x4b, - DW_AT_virtuality = 0x4c, - DW_AT_vtable_elem_location = 0x4d, - -// DWARF 3. - DW_AT_allocated = 0x4e, - DW_AT_associated = 0x4f, - DW_AT_data_location = 0x50, - DW_AT_byte_stride = 0x51, - DW_AT_entry_pc = 0x52, - DW_AT_use_UTF8 = 0x53, - DW_AT_extension = 0x54, - DW_AT_ranges = 0x55, - DW_AT_trampoline = 0x56, - DW_AT_call_column = 0x57, - DW_AT_call_file = 0x58, - DW_AT_call_line = 0x59, - DW_AT_description = 0x5a, - DW_AT_binary_scale = 0x5b, - DW_AT_decimal_scale = 0x5c, - DW_AT_small = 0x5d, - DW_AT_decimal_sign = 0x5e, - DW_AT_digit_count = 0x5f, - DW_AT_picture_string = 0x60, - DW_AT_mutable = 0x61, - DW_AT_threads_scaled = 0x62, - DW_AT_explicit = 0x63, - DW_AT_object_pointer = 0x64, - DW_AT_endianity = 0x65, - DW_AT_elemental = 0x66, - DW_AT_pure = 0x67, - DW_AT_recursive = 0x68, - -// DWARF 4. - DW_AT_signature = 0x69, - DW_AT_main_subprogram = 0x6a, - DW_AT_data_bit_offset = 0x6b, - DW_AT_const_expr = 0x6c, - DW_AT_enum_class = 0x6d, - DW_AT_linkage_name = 0x6e, - -// DWARF 5. - DW_AT_string_length_bit_size = 0x6f, - DW_AT_string_length_byte_size = 0x70, - DW_AT_rank = 0x71, - DW_AT_str_offsets_base = 0x72, - DW_AT_addr_base = 0x73, - DW_AT_rnglists_base = 0x74, - DW_AT_dwo_name = 0x76, - DW_AT_reference = 0x77, - DW_AT_rvalue_reference = 0x78, - DW_AT_macros = 0x79, - DW_AT_call_all_calls = 0x7a, - DW_AT_call_all_source_calls = 0x7b, - DW_AT_call_all_tail_calls = 0x7c, - DW_AT_call_return_pc = 0x7d, - DW_AT_call_value = 0x7e, - DW_AT_call_origin = 0x7f, - DW_AT_call_parameter = 0x80, - DW_AT_call_pc = 0x81, - DW_AT_call_tail_call = 0x82, - DW_AT_call_target = 0x83, - DW_AT_call_target_clobbered = 0x84, - DW_AT_call_data_location = 0x85, - DW_AT_call_data_value = 0x86, - DW_AT_noreturn = 0x87, - DW_AT_alignment = 0x88, - DW_AT_export_symbols = 0x89, - DW_AT_deleted = 0x8a, - DW_AT_defaulted = 0x8b, - DW_AT_loclists_base = 0x8c, - - DW_AT_lo_user = 0x2000, - DW_AT_hi_user = 0x3fff, - -// SGI/MIPS extensions. - DW_AT_MIPS_fde = 0x2001, - DW_AT_MIPS_loop_begin = 0x2002, - DW_AT_MIPS_tail_loop_begin = 0x2003, - DW_AT_MIPS_epilog_begin = 0x2004, - DW_AT_MIPS_loop_unroll_factor = 0x2005, - DW_AT_MIPS_software_pipeline_depth = 0x2006, - DW_AT_MIPS_linkage_name = 0x2007, - DW_AT_MIPS_stride = 0x2008, - DW_AT_MIPS_abstract_name = 0x2009, - DW_AT_MIPS_clone_origin = 0x200a, - DW_AT_MIPS_has_inlines = 0x200b, - DW_AT_MIPS_stride_byte = 0x200c, - DW_AT_MIPS_stride_elem = 0x200d, - DW_AT_MIPS_ptr_dopetype = 0x200e, - DW_AT_MIPS_allocatable_dopetype = 0x200f, - DW_AT_MIPS_assumed_shape_dopetype = 0x2010, - -// This one appears to have only been implemented by Open64 for -// fortran and may conflict with other extensions. - DW_AT_MIPS_assumed_size = 0x2011, - -// TODO: HP/CPQ extensions. -// These conflict with the MIPS extensions. - - DW_AT_INTEL_other_endian = 0x2026, - -// GNU extensions - DW_AT_sf_names = 0x2101, - DW_AT_src_info = 0x2102, - DW_AT_mac_info = 0x2103, - DW_AT_src_coords = 0x2104, - DW_AT_body_begin = 0x2105, - DW_AT_body_end = 0x2106, - DW_AT_GNU_vector = 0x2107, - DW_AT_GNU_guarded_by = 0x2108, - DW_AT_GNU_pt_guarded_by = 0x2109, - DW_AT_GNU_guarded = 0x210a, - DW_AT_GNU_pt_guarded = 0x210b, - DW_AT_GNU_locks_excluded = 0x210c, - DW_AT_GNU_exclusive_locks_required = 0x210d, - DW_AT_GNU_shared_locks_required = 0x210e, - DW_AT_GNU_odr_signature = 0x210f, - DW_AT_GNU_template_name = 0x2110, - DW_AT_GNU_call_site_value = 0x2111, - DW_AT_GNU_call_site_data_value = 0x2112, - DW_AT_GNU_call_site_target = 0x2113, - DW_AT_GNU_call_site_target_clobbered = 0x2114, - DW_AT_GNU_tail_call = 0x2115, - DW_AT_GNU_all_tail_call_sites = 0x2116, - DW_AT_GNU_all_call_sites = 0x2117, - DW_AT_GNU_all_source_call_sites = 0x2118, - DW_AT_GNU_macros = 0x2119, - DW_AT_GNU_deleted = 0x211a, - -// Extensions for Fission proposal. - DW_AT_GNU_dwo_name = 0x2130, - DW_AT_GNU_dwo_id = 0x2131, - DW_AT_GNU_ranges_base = 0x2132, - DW_AT_GNU_addr_base = 0x2133, - DW_AT_GNU_pubnames = 0x2134, - DW_AT_GNU_pubtypes = 0x2135, - DW_AT_GNU_discriminator = 0x2136, - DW_AT_GNU_locviews = 0x2137, - DW_AT_GNU_entry_view = 0x2138, - -// Conflict with Sun. -// DW_AT_VMS_rtnbeg_pd_address = 0x2201, - -// Sun extensions. - DW_AT_SUN_template = 0x2201, - DW_AT_SUN_alignment = 0x2202, - DW_AT_SUN_vtable = 0x2203, - DW_AT_SUN_count_guarantee = 0x2204, - DW_AT_SUN_command_line = 0x2205, - DW_AT_SUN_vbase = 0x2206, - DW_AT_SUN_compile_options = 0x2207, - DW_AT_SUN_language = 0x2208, - DW_AT_SUN_browser_file = 0x2209, - DW_AT_SUN_vtable_abi = 0x2210, - DW_AT_SUN_func_offsets = 0x2211, - DW_AT_SUN_cf_kind = 0x2212, - DW_AT_SUN_vtable_index = 0x2213, - DW_AT_SUN_omp_tpriv_addr = 0x2214, - DW_AT_SUN_omp_child_func = 0x2215, - DW_AT_SUN_func_offset = 0x2216, - DW_AT_SUN_memop_type_ref = 0x2217, - DW_AT_SUN_profile_id = 0x2218, - DW_AT_SUN_memop_signature = 0x2219, - DW_AT_SUN_obj_dir = 0x2220, - DW_AT_SUN_obj_file = 0x2221, - DW_AT_SUN_original_name = 0x2222, - DW_AT_SUN_hwcprof_signature = 0x2223, - DW_AT_SUN_amd64_parmdump = 0x2224, - DW_AT_SUN_part_link_name = 0x2225, - DW_AT_SUN_link_name = 0x2226, - DW_AT_SUN_pass_with_const = 0x2227, - DW_AT_SUN_return_with_const = 0x2228, - DW_AT_SUN_import_by_name = 0x2229, - DW_AT_SUN_f90_pointer = 0x222a, - DW_AT_SUN_pass_by_ref = 0x222b, - DW_AT_SUN_f90_allocatable = 0x222c, - DW_AT_SUN_f90_assumed_shape_array = 0x222d, - DW_AT_SUN_c_vla = 0x222e, - DW_AT_SUN_return_value_ptr = 0x2230, - DW_AT_SUN_dtor_start = 0x2231, - DW_AT_SUN_dtor_length = 0x2232, - DW_AT_SUN_dtor_state_initial = 0x2233, - DW_AT_SUN_dtor_state_final = 0x2234, - DW_AT_SUN_dtor_state_deltas = 0x2235, - DW_AT_SUN_import_by_lname = 0x2236, - DW_AT_SUN_f90_use_only = 0x2237, - DW_AT_SUN_namelist_spec = 0x2238, - DW_AT_SUN_is_omp_child_func = 0x2239, - DW_AT_SUN_fortran_main_alias = 0x223a, - DW_AT_SUN_fortran_based = 0x223b, - - DW_AT_ALTIUM_loclist = 0x2300, - - DW_AT_use_GNAT_descriptive_type = 0x2301, - DW_AT_GNAT_descriptive_type = 0x2302, - DW_AT_GNU_numerator = 0x2303, - DW_AT_GNU_denominator = 0x2304, - DW_AT_GNU_bias = 0x2305, - - DW_AT_upc_threads_scaled = 0x3210, - -// PGI (STMicroelectronics) extensions. - DW_AT_PGI_lbase = 0x3a00, - DW_AT_PGI_soffset = 0x3a01, - DW_AT_PGI_lstride = 0x3a02, - -// Borland extensions. - DW_AT_BORLAND_property_read = 0x3b11, - DW_AT_BORLAND_property_write = 0x3b12, - DW_AT_BORLAND_property_implements = 0x3b13, - DW_AT_BORLAND_property_index = 0x3b14, - DW_AT_BORLAND_property_default = 0x3b15, - DW_AT_BORLAND_Delphi_unit = 0x3b20, - DW_AT_BORLAND_Delphi_class = 0x3b21, - DW_AT_BORLAND_Delphi_record = 0x3b22, - DW_AT_BORLAND_Delphi_metaclass = 0x3b23, - DW_AT_BORLAND_Delphi_constructor = 0x3b24, - DW_AT_BORLAND_Delphi_destructor = 0x3b25, - DW_AT_BORLAND_Delphi_anonymous_method = 0x3b26, - DW_AT_BORLAND_Delphi_interface = 0x3b27, - DW_AT_BORLAND_Delphi_ABI = 0x3b28, - DW_AT_BORLAND_Delphi_return = 0x3b29, - DW_AT_BORLAND_Delphi_frameptr = 0x3b30, - DW_AT_BORLAND_closure = 0x3b31, - -// LLVM project extensions. - DW_AT_LLVM_include_path = 0x3e00, - DW_AT_LLVM_config_macros = 0x3e01, - DW_AT_LLVM_isysroot = 0x3e02, - -// Apple extensions. - DW_AT_APPLE_optimized = 0x3fe1, - DW_AT_APPLE_flags = 0x3fe2, - DW_AT_APPLE_isa = 0x3fe3, - DW_AT_APPLE_block = 0x3fe4, - DW_AT_APPLE_major_runtime_vers = 0x3fe5, - DW_AT_APPLE_runtime_class = 0x3fe6, - DW_AT_APPLE_omit_frame_ptr = 0x3fe7, - DW_AT_APPLE_property_name = 0x3fe8, - DW_AT_APPLE_property_getter = 0x3fe9, - DW_AT_APPLE_property_setter = 0x3fea, - DW_AT_APPLE_property_attribute = 0x3feb, - DW_AT_APPLE_objc_complete_type = 0x3fec, - DW_AT_APPLE_property = 0x3fed -}); - -dw!( -/// The attribute form encodings for DIE attributes. -/// -/// See Section 7.5.6, Table 7.6. -DwForm(u16) { - DW_FORM_null = 0x00, - - DW_FORM_addr = 0x01, - DW_FORM_block2 = 0x03, - DW_FORM_block4 = 0x04, - DW_FORM_data2 = 0x05, - DW_FORM_data4 = 0x06, - DW_FORM_data8 = 0x07, - DW_FORM_string = 0x08, - DW_FORM_block = 0x09, - DW_FORM_block1 = 0x0a, - DW_FORM_data1 = 0x0b, - DW_FORM_flag = 0x0c, - DW_FORM_sdata = 0x0d, - DW_FORM_strp = 0x0e, - DW_FORM_udata = 0x0f, - DW_FORM_ref_addr = 0x10, - DW_FORM_ref1 = 0x11, - DW_FORM_ref2 = 0x12, - DW_FORM_ref4 = 0x13, - DW_FORM_ref8 = 0x14, - DW_FORM_ref_udata = 0x15, - DW_FORM_indirect = 0x16, - -// DWARF 4. - DW_FORM_sec_offset = 0x17, - DW_FORM_exprloc = 0x18, - DW_FORM_flag_present = 0x19, - DW_FORM_ref_sig8 = 0x20, - -// DWARF 5. - DW_FORM_strx = 0x1a, - DW_FORM_addrx = 0x1b, - DW_FORM_ref_sup4 = 0x1c, - DW_FORM_strp_sup = 0x1d, - DW_FORM_data16 = 0x1e, - DW_FORM_line_strp = 0x1f, - DW_FORM_implicit_const = 0x21, - DW_FORM_loclistx = 0x22, - DW_FORM_rnglistx = 0x23, - DW_FORM_ref_sup8 = 0x24, - DW_FORM_strx1 = 0x25, - DW_FORM_strx2 = 0x26, - DW_FORM_strx3 = 0x27, - DW_FORM_strx4 = 0x28, - DW_FORM_addrx1 = 0x29, - DW_FORM_addrx2 = 0x2a, - DW_FORM_addrx3 = 0x2b, - DW_FORM_addrx4 = 0x2c, - -// Extensions for Fission proposal - DW_FORM_GNU_addr_index = 0x1f01, - DW_FORM_GNU_str_index = 0x1f02, - -// Alternate debug sections proposal (output of "dwz" tool). - DW_FORM_GNU_ref_alt = 0x1f20, - DW_FORM_GNU_strp_alt = 0x1f21 -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_encoding` attribute. -/// -/// See Section 7.8, Table 7.11. -DwAte(u8) { - DW_ATE_address = 0x01, - DW_ATE_boolean = 0x02, - DW_ATE_complex_float = 0x03, - DW_ATE_float = 0x04, - DW_ATE_signed = 0x05, - DW_ATE_signed_char = 0x06, - DW_ATE_unsigned = 0x07, - DW_ATE_unsigned_char = 0x08, - -// DWARF 3. - DW_ATE_imaginary_float = 0x09, - DW_ATE_packed_decimal = 0x0a, - DW_ATE_numeric_string = 0x0b, - DW_ATE_edited = 0x0c, - DW_ATE_signed_fixed = 0x0d, - DW_ATE_unsigned_fixed = 0x0e, - DW_ATE_decimal_float = 0x0f , - -// DWARF 4. - DW_ATE_UTF = 0x10, - DW_ATE_UCS = 0x11, - DW_ATE_ASCII = 0x12, - - DW_ATE_lo_user = 0x80, - DW_ATE_hi_user = 0xff, -}); - -dw!( -/// The encodings of the constants used in location list entries. -/// -/// See Section 7.7.3, Table 7.10. -DwLle(u8) { - DW_LLE_end_of_list = 0x00, - DW_LLE_base_addressx = 0x01, - DW_LLE_startx_endx = 0x02, - DW_LLE_startx_length = 0x03, - DW_LLE_offset_pair = 0x04, - DW_LLE_default_location = 0x05, - DW_LLE_base_address = 0x06, - DW_LLE_start_end = 0x07, - DW_LLE_start_length = 0x08, - DW_LLE_GNU_view_pair = 0x09, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_decimal_sign` attribute. -/// -/// See Section 7.8, Table 7.12. -DwDs(u8) { - DW_DS_unsigned = 0x01, - DW_DS_leading_overpunch = 0x02, - DW_DS_trailing_overpunch = 0x03, - DW_DS_leading_separate = 0x04, - DW_DS_trailing_separate = 0x05, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_endianity` attribute. -/// -/// See Section 7.8, Table 7.13. -DwEnd(u8) { - DW_END_default = 0x00, - DW_END_big = 0x01, - DW_END_little = 0x02, - DW_END_lo_user = 0x40, - DW_END_hi_user = 0xff, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_accessibility` attribute. -/// -/// See Section 7.9, Table 7.14. -DwAccess(u8) { - DW_ACCESS_public = 0x01, - DW_ACCESS_protected = 0x02, - DW_ACCESS_private = 0x03, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_visibility` attribute. -/// -/// See Section 7.10, Table 7.15. -DwVis(u8) { - DW_VIS_local = 0x01, - DW_VIS_exported = 0x02, - DW_VIS_qualified = 0x03, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_virtuality` attribute. -/// -/// See Section 7.11, Table 7.16. -DwVirtuality(u8) { - DW_VIRTUALITY_none = 0x00, - DW_VIRTUALITY_virtual = 0x01, - DW_VIRTUALITY_pure_virtual = 0x02, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_language` attribute. -/// -/// See Section 7.12, Table 7.17. -DwLang(u16) { - DW_LANG_C89 = 0x0001, - DW_LANG_C = 0x0002, - DW_LANG_Ada83 = 0x0003, - DW_LANG_C_plus_plus = 0x0004, - DW_LANG_Cobol74 = 0x0005, - DW_LANG_Cobol85 = 0x0006, - DW_LANG_Fortran77 = 0x0007, - DW_LANG_Fortran90 = 0x0008, - DW_LANG_Pascal83 = 0x0009, - DW_LANG_Modula2 = 0x000a, - DW_LANG_Java = 0x000b, - DW_LANG_C99 = 0x000c, - DW_LANG_Ada95 = 0x000d, - DW_LANG_Fortran95 = 0x000e, - DW_LANG_PLI = 0x000f, - DW_LANG_ObjC = 0x0010, - DW_LANG_ObjC_plus_plus = 0x0011, - DW_LANG_UPC = 0x0012, - DW_LANG_D = 0x0013, - DW_LANG_Python = 0x0014, - DW_LANG_OpenCL = 0x0015, - DW_LANG_Go = 0x0016, - DW_LANG_Modula3 = 0x0017, - DW_LANG_Haskell = 0x0018, - DW_LANG_C_plus_plus_03 = 0x0019, - DW_LANG_C_plus_plus_11 = 0x001a, - DW_LANG_OCaml = 0x001b, - DW_LANG_Rust = 0x001c, - DW_LANG_C11 = 0x001d, - DW_LANG_Swift = 0x001e, - DW_LANG_Julia = 0x001f, - DW_LANG_Dylan = 0x0020, - DW_LANG_C_plus_plus_14 = 0x0021, - DW_LANG_Fortran03 = 0x0022, - DW_LANG_Fortran08 = 0x0023, - DW_LANG_RenderScript = 0x0024, - DW_LANG_BLISS = 0x0025, - DW_LANG_Kotlin = 0x0026, - DW_LANG_Zig = 0x0027, - DW_LANG_Crystal = 0x0028, - DW_LANG_C_plus_plus_17 = 0x002a, - DW_LANG_C_plus_plus_20 = 0x002b, - DW_LANG_C17 = 0x002c, - DW_LANG_Fortran18 = 0x002d, - DW_LANG_Ada2005 = 0x002e, - DW_LANG_Ada2012 = 0x002f, - - DW_LANG_lo_user = 0x8000, - DW_LANG_hi_user = 0xffff, - - DW_LANG_Mips_Assembler = 0x8001, - DW_LANG_GOOGLE_RenderScript = 0x8e57, - DW_LANG_SUN_Assembler = 0x9001, - DW_LANG_ALTIUM_Assembler = 0x9101, - DW_LANG_BORLAND_Delphi = 0xb000, -}); - -impl DwLang { - /// Get the default DW_AT_lower_bound for this language. - pub fn default_lower_bound(self) -> Option<usize> { - match self { - DW_LANG_C89 - | DW_LANG_C - | DW_LANG_C_plus_plus - | DW_LANG_Java - | DW_LANG_C99 - | DW_LANG_ObjC - | DW_LANG_ObjC_plus_plus - | DW_LANG_UPC - | DW_LANG_D - | DW_LANG_Python - | DW_LANG_OpenCL - | DW_LANG_Go - | DW_LANG_Haskell - | DW_LANG_C_plus_plus_03 - | DW_LANG_C_plus_plus_11 - | DW_LANG_OCaml - | DW_LANG_Rust - | DW_LANG_C11 - | DW_LANG_Swift - | DW_LANG_Dylan - | DW_LANG_C_plus_plus_14 - | DW_LANG_RenderScript - | DW_LANG_BLISS => Some(0), - DW_LANG_Ada83 | DW_LANG_Cobol74 | DW_LANG_Cobol85 | DW_LANG_Fortran77 - | DW_LANG_Fortran90 | DW_LANG_Pascal83 | DW_LANG_Modula2 | DW_LANG_Ada95 - | DW_LANG_Fortran95 | DW_LANG_PLI | DW_LANG_Modula3 | DW_LANG_Julia - | DW_LANG_Fortran03 | DW_LANG_Fortran08 => Some(1), - _ => None, - } - } -} - -dw!( -/// The encodings of the constants used in the `DW_AT_address_class` attribute. -/// -/// There is only one value that is common to all target architectures. -/// See Section 7.13. -DwAddr(u64) { - DW_ADDR_none = 0x00, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_identifier_case` attribute. -/// -/// See Section 7.14, Table 7.18. -DwId(u8) { - DW_ID_case_sensitive = 0x00, - DW_ID_up_case = 0x01, - DW_ID_down_case = 0x02, - DW_ID_case_insensitive = 0x03, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_calling_convention` attribute. -/// -/// See Section 7.15, Table 7.19. -DwCc(u8) { - DW_CC_normal = 0x01, - DW_CC_program = 0x02, - DW_CC_nocall = 0x03, - DW_CC_pass_by_reference = 0x04, - DW_CC_pass_by_value = 0x05, - DW_CC_lo_user = 0x40, - DW_CC_hi_user = 0xff, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_inline` attribute. -/// -/// See Section 7.16, Table 7.20. -DwInl(u8) { - DW_INL_not_inlined = 0x00, - DW_INL_inlined = 0x01, - DW_INL_declared_not_inlined = 0x02, - DW_INL_declared_inlined = 0x03, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_ordering` attribute. -/// -/// See Section 7.17, Table 7.17. -DwOrd(u8) { - DW_ORD_row_major = 0x00, - DW_ORD_col_major = 0x01, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_discr_list` attribute. -/// -/// See Section 7.18, Table 7.22. -DwDsc(u8) { - DW_DSC_label = 0x00, - DW_DSC_range = 0x01, -}); - -dw!( -/// Name index attribute encodings. -/// -/// See Section 7.19, Table 7.23. -DwIdx(u16) { - DW_IDX_compile_unit = 1, - DW_IDX_type_unit = 2, - DW_IDX_die_offset = 3, - DW_IDX_parent = 4, - DW_IDX_type_hash = 5, - DW_IDX_lo_user = 0x2000, - DW_IDX_hi_user = 0x3fff, -}); - -dw!( -/// The encodings of the constants used in the `DW_AT_defaulted` attribute. -/// -/// See Section 7.20, Table 7.24. -DwDefaulted(u8) { - DW_DEFAULTED_no = 0x00, - DW_DEFAULTED_in_class = 0x01, - DW_DEFAULTED_out_of_class = 0x02, -}); - -dw!( -/// The encodings for the standard opcodes for line number information. -/// -/// See Section 7.22, Table 7.25. -DwLns(u8) { - DW_LNS_copy = 0x01, - DW_LNS_advance_pc = 0x02, - DW_LNS_advance_line = 0x03, - DW_LNS_set_file = 0x04, - DW_LNS_set_column = 0x05, - DW_LNS_negate_stmt = 0x06, - DW_LNS_set_basic_block = 0x07, - DW_LNS_const_add_pc = 0x08, - DW_LNS_fixed_advance_pc = 0x09, - DW_LNS_set_prologue_end = 0x0a, - DW_LNS_set_epilogue_begin = 0x0b, - DW_LNS_set_isa = 0x0c, -}); - -dw!( -/// The encodings for the extended opcodes for line number information. -/// -/// See Section 7.22, Table 7.26. -DwLne(u8) { - DW_LNE_end_sequence = 0x01, - DW_LNE_set_address = 0x02, - DW_LNE_define_file = 0x03, - DW_LNE_set_discriminator = 0x04, - - DW_LNE_lo_user = 0x80, - DW_LNE_hi_user = 0xff, -}); - -dw!( -/// The encodings for the line number header entry formats. -/// -/// See Section 7.22, Table 7.27. -DwLnct(u16) { - DW_LNCT_path = 0x1, - DW_LNCT_directory_index = 0x2, - DW_LNCT_timestamp = 0x3, - DW_LNCT_size = 0x4, - DW_LNCT_MD5 = 0x5, - DW_LNCT_lo_user = 0x2000, - DW_LNCT_hi_user = 0x3fff, -}); - -dw!( -/// The encodings for macro information entry types. -/// -/// See Section 7.23, Table 7.28. -DwMacro(u8) { - DW_MACRO_define = 0x01, - DW_MACRO_undef = 0x02, - DW_MACRO_start_file = 0x03, - DW_MACRO_end_file = 0x04, - DW_MACRO_define_strp = 0x05, - DW_MACRO_undef_strp = 0x06, - DW_MACRO_import = 0x07, - DW_MACRO_define_sup = 0x08, - DW_MACRO_undef_sup = 0x09, - DW_MACRO_import_sup = 0x0a, - DW_MACRO_define_strx = 0x0b, - DW_MACRO_undef_strx = 0x0c, - DW_MACRO_lo_user = 0xe0, - DW_MACRO_hi_user = 0xff, -}); - -dw!( -/// Range list entry encoding values. -/// -/// See Section 7.25, Table 7.30. -DwRle(u8) { - DW_RLE_end_of_list = 0x00, - DW_RLE_base_addressx = 0x01, - DW_RLE_startx_endx = 0x02, - DW_RLE_startx_length = 0x03, - DW_RLE_offset_pair = 0x04, - DW_RLE_base_address = 0x05, - DW_RLE_start_end = 0x06, - DW_RLE_start_length = 0x07, -}); - -dw!( -/// The encodings for DWARF expression operations. -/// -/// See Section 7.7.1, Table 7.9. -DwOp(u8) { - DW_OP_addr = 0x03, - DW_OP_deref = 0x06, - DW_OP_const1u = 0x08, - DW_OP_const1s = 0x09, - DW_OP_const2u = 0x0a, - DW_OP_const2s = 0x0b, - DW_OP_const4u = 0x0c, - DW_OP_const4s = 0x0d, - DW_OP_const8u = 0x0e, - DW_OP_const8s = 0x0f, - DW_OP_constu = 0x10, - DW_OP_consts = 0x11, - DW_OP_dup = 0x12, - DW_OP_drop = 0x13, - DW_OP_over = 0x14, - DW_OP_pick = 0x15, - DW_OP_swap = 0x16, - DW_OP_rot = 0x17, - DW_OP_xderef = 0x18, - DW_OP_abs = 0x19, - DW_OP_and = 0x1a, - DW_OP_div = 0x1b, - DW_OP_minus = 0x1c, - DW_OP_mod = 0x1d, - DW_OP_mul = 0x1e, - DW_OP_neg = 0x1f, - DW_OP_not = 0x20, - DW_OP_or = 0x21, - DW_OP_plus = 0x22, - DW_OP_plus_uconst = 0x23, - DW_OP_shl = 0x24, - DW_OP_shr = 0x25, - DW_OP_shra = 0x26, - DW_OP_xor = 0x27, - DW_OP_bra = 0x28, - DW_OP_eq = 0x29, - DW_OP_ge = 0x2a, - DW_OP_gt = 0x2b, - DW_OP_le = 0x2c, - DW_OP_lt = 0x2d, - DW_OP_ne = 0x2e, - DW_OP_skip = 0x2f, - DW_OP_lit0 = 0x30, - DW_OP_lit1 = 0x31, - DW_OP_lit2 = 0x32, - DW_OP_lit3 = 0x33, - DW_OP_lit4 = 0x34, - DW_OP_lit5 = 0x35, - DW_OP_lit6 = 0x36, - DW_OP_lit7 = 0x37, - DW_OP_lit8 = 0x38, - DW_OP_lit9 = 0x39, - DW_OP_lit10 = 0x3a, - DW_OP_lit11 = 0x3b, - DW_OP_lit12 = 0x3c, - DW_OP_lit13 = 0x3d, - DW_OP_lit14 = 0x3e, - DW_OP_lit15 = 0x3f, - DW_OP_lit16 = 0x40, - DW_OP_lit17 = 0x41, - DW_OP_lit18 = 0x42, - DW_OP_lit19 = 0x43, - DW_OP_lit20 = 0x44, - DW_OP_lit21 = 0x45, - DW_OP_lit22 = 0x46, - DW_OP_lit23 = 0x47, - DW_OP_lit24 = 0x48, - DW_OP_lit25 = 0x49, - DW_OP_lit26 = 0x4a, - DW_OP_lit27 = 0x4b, - DW_OP_lit28 = 0x4c, - DW_OP_lit29 = 0x4d, - DW_OP_lit30 = 0x4e, - DW_OP_lit31 = 0x4f, - DW_OP_reg0 = 0x50, - DW_OP_reg1 = 0x51, - DW_OP_reg2 = 0x52, - DW_OP_reg3 = 0x53, - DW_OP_reg4 = 0x54, - DW_OP_reg5 = 0x55, - DW_OP_reg6 = 0x56, - DW_OP_reg7 = 0x57, - DW_OP_reg8 = 0x58, - DW_OP_reg9 = 0x59, - DW_OP_reg10 = 0x5a, - DW_OP_reg11 = 0x5b, - DW_OP_reg12 = 0x5c, - DW_OP_reg13 = 0x5d, - DW_OP_reg14 = 0x5e, - DW_OP_reg15 = 0x5f, - DW_OP_reg16 = 0x60, - DW_OP_reg17 = 0x61, - DW_OP_reg18 = 0x62, - DW_OP_reg19 = 0x63, - DW_OP_reg20 = 0x64, - DW_OP_reg21 = 0x65, - DW_OP_reg22 = 0x66, - DW_OP_reg23 = 0x67, - DW_OP_reg24 = 0x68, - DW_OP_reg25 = 0x69, - DW_OP_reg26 = 0x6a, - DW_OP_reg27 = 0x6b, - DW_OP_reg28 = 0x6c, - DW_OP_reg29 = 0x6d, - DW_OP_reg30 = 0x6e, - DW_OP_reg31 = 0x6f, - DW_OP_breg0 = 0x70, - DW_OP_breg1 = 0x71, - DW_OP_breg2 = 0x72, - DW_OP_breg3 = 0x73, - DW_OP_breg4 = 0x74, - DW_OP_breg5 = 0x75, - DW_OP_breg6 = 0x76, - DW_OP_breg7 = 0x77, - DW_OP_breg8 = 0x78, - DW_OP_breg9 = 0x79, - DW_OP_breg10 = 0x7a, - DW_OP_breg11 = 0x7b, - DW_OP_breg12 = 0x7c, - DW_OP_breg13 = 0x7d, - DW_OP_breg14 = 0x7e, - DW_OP_breg15 = 0x7f, - DW_OP_breg16 = 0x80, - DW_OP_breg17 = 0x81, - DW_OP_breg18 = 0x82, - DW_OP_breg19 = 0x83, - DW_OP_breg20 = 0x84, - DW_OP_breg21 = 0x85, - DW_OP_breg22 = 0x86, - DW_OP_breg23 = 0x87, - DW_OP_breg24 = 0x88, - DW_OP_breg25 = 0x89, - DW_OP_breg26 = 0x8a, - DW_OP_breg27 = 0x8b, - DW_OP_breg28 = 0x8c, - DW_OP_breg29 = 0x8d, - DW_OP_breg30 = 0x8e, - DW_OP_breg31 = 0x8f, - DW_OP_regx = 0x90, - DW_OP_fbreg = 0x91, - DW_OP_bregx = 0x92, - DW_OP_piece = 0x93, - DW_OP_deref_size = 0x94, - DW_OP_xderef_size = 0x95, - DW_OP_nop = 0x96, - DW_OP_push_object_address = 0x97, - DW_OP_call2 = 0x98, - DW_OP_call4 = 0x99, - DW_OP_call_ref = 0x9a, - DW_OP_form_tls_address = 0x9b, - DW_OP_call_frame_cfa = 0x9c, - DW_OP_bit_piece = 0x9d, - DW_OP_implicit_value = 0x9e, - DW_OP_stack_value = 0x9f, - DW_OP_implicit_pointer = 0xa0, - DW_OP_addrx = 0xa1, - DW_OP_constx = 0xa2, - DW_OP_entry_value = 0xa3, - DW_OP_const_type = 0xa4, - DW_OP_regval_type = 0xa5, - DW_OP_deref_type = 0xa6, - DW_OP_xderef_type = 0xa7, - DW_OP_convert = 0xa8, - DW_OP_reinterpret = 0xa9, - - // GNU extensions - DW_OP_GNU_push_tls_address = 0xe0, - DW_OP_GNU_implicit_pointer = 0xf2, - DW_OP_GNU_entry_value = 0xf3, - DW_OP_GNU_const_type = 0xf4, - DW_OP_GNU_regval_type = 0xf5, - DW_OP_GNU_deref_type = 0xf6, - DW_OP_GNU_convert = 0xf7, - DW_OP_GNU_reinterpret = 0xf9, - DW_OP_GNU_parameter_ref = 0xfa, - DW_OP_GNU_addr_index = 0xfb, - DW_OP_GNU_const_index = 0xfc, - - // Wasm extensions - DW_OP_WASM_location = 0xed, -}); - -dw!( -/// Pointer encoding used by `.eh_frame`. -/// -/// The four lower bits describe the -/// format of the pointer, the upper four bits describe how the encoding should -/// be applied. -/// -/// Defined in `<https://refspecs.linuxfoundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html>` -DwEhPe(u8) { -// Format of pointer encoding. - -// "Unsigned value is encoded using the Little Endian Base 128" - DW_EH_PE_uleb128 = 0x1, -// "A 2 bytes unsigned value." - DW_EH_PE_udata2 = 0x2, -// "A 4 bytes unsigned value." - DW_EH_PE_udata4 = 0x3, -// "An 8 bytes unsigned value." - DW_EH_PE_udata8 = 0x4, -// "Signed value is encoded using the Little Endian Base 128" - DW_EH_PE_sleb128 = 0x9, -// "A 2 bytes signed value." - DW_EH_PE_sdata2 = 0x0a, -// "A 4 bytes signed value." - DW_EH_PE_sdata4 = 0x0b, -// "An 8 bytes signed value." - DW_EH_PE_sdata8 = 0x0c, - -// How the pointer encoding should be applied. - -// `DW_EH_PE_pcrel` pointers are relative to their own location. - DW_EH_PE_pcrel = 0x10, -// "Value is relative to the beginning of the .text section." - DW_EH_PE_textrel = 0x20, -// "Value is relative to the beginning of the .got or .eh_frame_hdr section." - DW_EH_PE_datarel = 0x30, -// "Value is relative to the beginning of the function." - DW_EH_PE_funcrel = 0x40, -// "Value is aligned to an address unit sized boundary." - DW_EH_PE_aligned = 0x50, - -// This bit can be set for any of the above encoding applications. When set, -// the encoded value is the address of the real pointer result, not the -// pointer result itself. -// -// This isn't defined in the DWARF or the `.eh_frame` standards, but is -// generated by both GNU/Linux and macOS tooling. - DW_EH_PE_indirect = 0x80, - -// These constants apply to both the lower and upper bits. - -// "The Value is a literal pointer whose size is determined by the -// architecture." - DW_EH_PE_absptr = 0x0, -// The absence of a pointer and encoding. - DW_EH_PE_omit = 0xff, -}); - -const DW_EH_PE_FORMAT_MASK: u8 = 0b0000_1111; - -// Ignores indirection bit. -const DW_EH_PE_APPLICATION_MASK: u8 = 0b0111_0000; - -impl DwEhPe { - /// Get the pointer encoding's format. - #[inline] - pub fn format(self) -> DwEhPe { - DwEhPe(self.0 & DW_EH_PE_FORMAT_MASK) - } - - /// Get the pointer encoding's application. - #[inline] - pub fn application(self) -> DwEhPe { - DwEhPe(self.0 & DW_EH_PE_APPLICATION_MASK) - } - - /// Is this encoding the absent pointer encoding? - #[inline] - pub fn is_absent(self) -> bool { - self == DW_EH_PE_omit - } - - /// Is this coding indirect? If so, its encoded value is the address of the - /// real pointer result, not the pointer result itself. - #[inline] - pub fn is_indirect(self) -> bool { - self.0 & DW_EH_PE_indirect.0 != 0 - } - - /// Is this a known, valid pointer encoding? - pub fn is_valid_encoding(self) -> bool { - if self.is_absent() { - return true; - } - - match self.format() { - DW_EH_PE_absptr | DW_EH_PE_uleb128 | DW_EH_PE_udata2 | DW_EH_PE_udata4 - | DW_EH_PE_udata8 | DW_EH_PE_sleb128 | DW_EH_PE_sdata2 | DW_EH_PE_sdata4 - | DW_EH_PE_sdata8 => {} - _ => return false, - } - - match self.application() { - DW_EH_PE_absptr | DW_EH_PE_pcrel | DW_EH_PE_textrel | DW_EH_PE_datarel - | DW_EH_PE_funcrel | DW_EH_PE_aligned => {} - _ => return false, - } - - true - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_dw_eh_pe_format() { - let encoding = DwEhPe(DW_EH_PE_pcrel.0 | DW_EH_PE_uleb128.0); - assert_eq!(encoding.format(), DW_EH_PE_uleb128); - } - - #[test] - fn test_dw_eh_pe_application() { - let encoding = DwEhPe(DW_EH_PE_pcrel.0 | DW_EH_PE_uleb128.0); - assert_eq!(encoding.application(), DW_EH_PE_pcrel); - } - - #[test] - fn test_dw_eh_pe_is_absent() { - assert_eq!(DW_EH_PE_absptr.is_absent(), false); - assert_eq!(DW_EH_PE_omit.is_absent(), true); - } - - #[test] - fn test_dw_eh_pe_is_valid_encoding_ok() { - let encoding = DwEhPe(DW_EH_PE_uleb128.0 | DW_EH_PE_pcrel.0); - assert!(encoding.is_valid_encoding()); - assert!(DW_EH_PE_absptr.is_valid_encoding()); - assert!(DW_EH_PE_omit.is_valid_encoding()); - } - - #[test] - fn test_dw_eh_pe_is_valid_encoding_bad_format() { - let encoding = DwEhPe((DW_EH_PE_sdata8.0 + 1) | DW_EH_PE_pcrel.0); - assert_eq!(encoding.is_valid_encoding(), false); - } - - #[test] - fn test_dw_eh_pe_is_valid_encoding_bad_application() { - let encoding = DwEhPe(DW_EH_PE_sdata8.0 | (DW_EH_PE_aligned.0 + 1)); - assert_eq!(encoding.is_valid_encoding(), false); - } -} diff --git a/vendor/gimli/src/endianity.rs b/vendor/gimli/src/endianity.rs deleted file mode 100644 index 3201551..0000000 --- a/vendor/gimli/src/endianity.rs +++ /dev/null @@ -1,256 +0,0 @@ -//! Types for compile-time and run-time endianity. - -use core::convert::TryInto; -use core::fmt::Debug; - -/// A trait describing the endianity of some buffer. -pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq { - /// Return true for big endian byte order. - fn is_big_endian(self) -> bool; - - /// Return true for little endian byte order. - #[inline] - fn is_little_endian(self) -> bool { - !self.is_big_endian() - } - - /// Reads an unsigned 16 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 2`. - #[inline] - fn read_u16(self, buf: &[u8]) -> u16 { - let bytes: &[u8; 2] = buf[..2].try_into().unwrap(); - if self.is_big_endian() { - u16::from_be_bytes(*bytes) - } else { - u16::from_le_bytes(*bytes) - } - } - - /// Reads an unsigned 32 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - #[inline] - fn read_u32(self, buf: &[u8]) -> u32 { - let bytes: &[u8; 4] = buf[..4].try_into().unwrap(); - if self.is_big_endian() { - u32::from_be_bytes(*bytes) - } else { - u32::from_le_bytes(*bytes) - } - } - - /// Reads an unsigned 64 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - #[inline] - fn read_u64(self, buf: &[u8]) -> u64 { - let bytes: &[u8; 8] = buf[..8].try_into().unwrap(); - if self.is_big_endian() { - u64::from_be_bytes(*bytes) - } else { - u64::from_le_bytes(*bytes) - } - } - - /// Read an unsigned n-bytes integer u64. - /// - /// # Panics - /// - /// Panics when `buf.len() < 1` or `buf.len() > 8`. - #[inline] - fn read_uint(&mut self, buf: &[u8]) -> u64 { - let mut tmp = [0; 8]; - if self.is_big_endian() { - tmp[8 - buf.len()..].copy_from_slice(buf); - } else { - tmp[..buf.len()].copy_from_slice(buf); - } - self.read_u64(&tmp) - } - - /// Reads a signed 16 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 2`. - #[inline] - fn read_i16(self, buf: &[u8]) -> i16 { - self.read_u16(buf) as i16 - } - - /// Reads a signed 32 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - #[inline] - fn read_i32(self, buf: &[u8]) -> i32 { - self.read_u32(buf) as i32 - } - - /// Reads a signed 64 bit integer from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - #[inline] - fn read_i64(self, buf: &[u8]) -> i64 { - self.read_u64(buf) as i64 - } - - /// Reads a 32 bit floating point number from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - #[inline] - fn read_f32(self, buf: &[u8]) -> f32 { - f32::from_bits(self.read_u32(buf)) - } - - /// Reads a 32 bit floating point number from `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - #[inline] - fn read_f64(self, buf: &[u8]) -> f64 { - f64::from_bits(self.read_u64(buf)) - } - - /// Writes an unsigned 16 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 2`. - #[inline] - fn write_u16(self, buf: &mut [u8], n: u16) { - let bytes = if self.is_big_endian() { - n.to_be_bytes() - } else { - n.to_le_bytes() - }; - buf[..2].copy_from_slice(&bytes); - } - - /// Writes an unsigned 32 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 4`. - #[inline] - fn write_u32(self, buf: &mut [u8], n: u32) { - let bytes = if self.is_big_endian() { - n.to_be_bytes() - } else { - n.to_le_bytes() - }; - buf[..4].copy_from_slice(&bytes); - } - - /// Writes an unsigned 64 bit integer `n` to `buf`. - /// - /// # Panics - /// - /// Panics when `buf.len() < 8`. - #[inline] - fn write_u64(self, buf: &mut [u8], n: u64) { - let bytes = if self.is_big_endian() { - n.to_be_bytes() - } else { - n.to_le_bytes() - }; - buf[..8].copy_from_slice(&bytes); - } -} - -/// Byte order that is selectable at runtime. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum RunTimeEndian { - /// Little endian byte order. - Little, - /// Big endian byte order. - Big, -} - -impl Default for RunTimeEndian { - #[cfg(target_endian = "little")] - #[inline] - fn default() -> RunTimeEndian { - RunTimeEndian::Little - } - - #[cfg(target_endian = "big")] - #[inline] - fn default() -> RunTimeEndian { - RunTimeEndian::Big - } -} - -impl Endianity for RunTimeEndian { - #[inline] - fn is_big_endian(self) -> bool { - self != RunTimeEndian::Little - } -} - -/// Little endian byte order. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct LittleEndian; - -impl Default for LittleEndian { - #[inline] - fn default() -> LittleEndian { - LittleEndian - } -} - -impl Endianity for LittleEndian { - #[inline] - fn is_big_endian(self) -> bool { - false - } -} - -/// Big endian byte order. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct BigEndian; - -impl Default for BigEndian { - #[inline] - fn default() -> BigEndian { - BigEndian - } -} - -impl Endianity for BigEndian { - #[inline] - fn is_big_endian(self) -> bool { - true - } -} - -/// The native endianity for the target platform. -#[cfg(target_endian = "little")] -pub type NativeEndian = LittleEndian; - -#[cfg(target_endian = "little")] -#[allow(non_upper_case_globals)] -#[doc(hidden)] -pub const NativeEndian: LittleEndian = LittleEndian; - -/// The native endianity for the target platform. -#[cfg(target_endian = "big")] -pub type NativeEndian = BigEndian; - -#[cfg(target_endian = "big")] -#[allow(non_upper_case_globals)] -#[doc(hidden)] -pub const NativeEndian: BigEndian = BigEndian; diff --git a/vendor/gimli/src/leb128.rs b/vendor/gimli/src/leb128.rs deleted file mode 100644 index de81cfd..0000000 --- a/vendor/gimli/src/leb128.rs +++ /dev/null @@ -1,612 +0,0 @@ -//! Read and write DWARF's "Little Endian Base 128" (LEB128) variable length -//! integer encoding. -//! -//! The implementation is a direct translation of the psuedocode in the DWARF 4 -//! standard's appendix C. -//! -//! Read and write signed integers: -//! -//! ``` -//! # #[cfg(all(feature = "read", feature = "write"))] { -//! use gimli::{EndianSlice, NativeEndian, leb128}; -//! -//! let mut buf = [0; 1024]; -//! -//! // Write to anything that implements `std::io::Write`. -//! { -//! let mut writable = &mut buf[..]; -//! leb128::write::signed(&mut writable, -12345).expect("Should write number"); -//! } -//! -//! // Read from anything that implements `gimli::Reader`. -//! let mut readable = EndianSlice::new(&buf[..], NativeEndian); -//! let val = leb128::read::signed(&mut readable).expect("Should read number"); -//! assert_eq!(val, -12345); -//! # } -//! ``` -//! -//! Or read and write unsigned integers: -//! -//! ``` -//! # #[cfg(all(feature = "read", feature = "write"))] { -//! use gimli::{EndianSlice, NativeEndian, leb128}; -//! -//! let mut buf = [0; 1024]; -//! -//! { -//! let mut writable = &mut buf[..]; -//! leb128::write::unsigned(&mut writable, 98765).expect("Should write number"); -//! } -//! -//! let mut readable = EndianSlice::new(&buf[..], NativeEndian); -//! let val = leb128::read::unsigned(&mut readable).expect("Should read number"); -//! assert_eq!(val, 98765); -//! # } -//! ``` - -const CONTINUATION_BIT: u8 = 1 << 7; -#[cfg(feature = "read-core")] -const SIGN_BIT: u8 = 1 << 6; - -#[inline] -fn low_bits_of_byte(byte: u8) -> u8 { - byte & !CONTINUATION_BIT -} - -#[inline] -#[allow(dead_code)] -fn low_bits_of_u64(val: u64) -> u8 { - let byte = val & u64::from(core::u8::MAX); - low_bits_of_byte(byte as u8) -} - -/// A module for reading signed and unsigned integers that have been LEB128 -/// encoded. -#[cfg(feature = "read-core")] -pub mod read { - use super::{low_bits_of_byte, CONTINUATION_BIT, SIGN_BIT}; - use crate::read::{Error, Reader, Result}; - - /// Read bytes until the LEB128 continuation bit is not set. - pub fn skip<R: Reader>(r: &mut R) -> Result<()> { - loop { - let byte = r.read_u8()?; - if byte & CONTINUATION_BIT == 0 { - return Ok(()); - } - } - } - - /// Read an unsigned LEB128 number from the given `Reader` and - /// return it or an error if reading failed. - pub fn unsigned<R: Reader>(r: &mut R) -> Result<u64> { - let mut result = 0; - let mut shift = 0; - - loop { - let byte = r.read_u8()?; - if shift == 63 && byte != 0x00 && byte != 0x01 { - return Err(Error::BadUnsignedLeb128); - } - - let low_bits = u64::from(low_bits_of_byte(byte)); - result |= low_bits << shift; - - if byte & CONTINUATION_BIT == 0 { - return Ok(result); - } - - shift += 7; - } - } - - /// Read an LEB128 u16 from the given `Reader` and - /// return it or an error if reading failed. - pub fn u16<R: Reader>(r: &mut R) -> Result<u16> { - let byte = r.read_u8()?; - let mut result = u16::from(low_bits_of_byte(byte)); - if byte & CONTINUATION_BIT == 0 { - return Ok(result); - } - - let byte = r.read_u8()?; - result |= u16::from(low_bits_of_byte(byte)) << 7; - if byte & CONTINUATION_BIT == 0 { - return Ok(result); - } - - let byte = r.read_u8()?; - if byte > 0x03 { - return Err(Error::BadUnsignedLeb128); - } - result += u16::from(byte) << 14; - Ok(result) - } - - /// Read a signed LEB128 number from the given `Reader` and - /// return it or an error if reading failed. - pub fn signed<R: Reader>(r: &mut R) -> Result<i64> { - let mut result = 0; - let mut shift = 0; - let size = 64; - let mut byte; - - loop { - byte = r.read_u8()?; - if shift == 63 && byte != 0x00 && byte != 0x7f { - return Err(Error::BadSignedLeb128); - } - - let low_bits = i64::from(low_bits_of_byte(byte)); - result |= low_bits << shift; - shift += 7; - - if byte & CONTINUATION_BIT == 0 { - break; - } - } - - if shift < size && (SIGN_BIT & byte) == SIGN_BIT { - // Sign extend the result. - result |= !0 << shift; - } - - Ok(result) - } -} - -/// A module for writing integers encoded as LEB128. -#[cfg(feature = "write")] -pub mod write { - use super::{low_bits_of_u64, CONTINUATION_BIT}; - use std::io; - - /// Write the given unsigned number using the LEB128 encoding to the given - /// `std::io::Write`able. Returns the number of bytes written to `w`, or an - /// error if writing failed. - pub fn unsigned<W>(w: &mut W, mut val: u64) -> Result<usize, io::Error> - where - W: io::Write, - { - let mut bytes_written = 0; - loop { - let mut byte = low_bits_of_u64(val); - val >>= 7; - if val != 0 { - // More bytes to come, so set the continuation bit. - byte |= CONTINUATION_BIT; - } - - let buf = [byte]; - w.write_all(&buf)?; - bytes_written += 1; - - if val == 0 { - return Ok(bytes_written); - } - } - } - - /// Return the size of the LEB128 encoding of the given unsigned number. - pub fn uleb128_size(mut val: u64) -> usize { - let mut size = 0; - loop { - val >>= 7; - size += 1; - if val == 0 { - return size; - } - } - } - - /// Write the given signed number using the LEB128 encoding to the given - /// `std::io::Write`able. Returns the number of bytes written to `w`, or an - /// error if writing failed. - pub fn signed<W>(w: &mut W, mut val: i64) -> Result<usize, io::Error> - where - W: io::Write, - { - let mut bytes_written = 0; - loop { - let mut byte = val as u8; - // Keep the sign bit for testing - val >>= 6; - let done = val == 0 || val == -1; - if done { - byte &= !CONTINUATION_BIT; - } else { - // Remove the sign bit - val >>= 1; - // More bytes to come, so set the continuation bit. - byte |= CONTINUATION_BIT; - } - - let buf = [byte]; - w.write_all(&buf)?; - bytes_written += 1; - - if done { - return Ok(bytes_written); - } - } - } - - /// Return the size of the LEB128 encoding of the given signed number. - pub fn sleb128_size(mut val: i64) -> usize { - let mut size = 0; - loop { - val >>= 6; - let done = val == 0 || val == -1; - val >>= 1; - size += 1; - if done { - return size; - } - } - } -} - -#[cfg(test)] -#[cfg(all(feature = "read", feature = "write"))] -mod tests { - use super::{low_bits_of_byte, low_bits_of_u64, read, write, CONTINUATION_BIT}; - use crate::endianity::NativeEndian; - use crate::read::{EndianSlice, Error, ReaderOffsetId}; - - trait ResultExt { - fn map_eof(self, input: &[u8]) -> Self; - } - - impl<T> ResultExt for Result<T, Error> { - fn map_eof(self, input: &[u8]) -> Self { - match self { - Err(Error::UnexpectedEof(id)) => { - let id = ReaderOffsetId(id.0 - input.as_ptr() as u64); - Err(Error::UnexpectedEof(id)) - } - r => r, - } - } - } - - #[test] - fn test_low_bits_of_byte() { - for i in 0..127 { - assert_eq!(i, low_bits_of_byte(i)); - assert_eq!(i, low_bits_of_byte(i | CONTINUATION_BIT)); - } - } - - #[test] - fn test_low_bits_of_u64() { - for i in 0u64..127 { - assert_eq!(i as u8, low_bits_of_u64(1 << 16 | i)); - assert_eq!( - i as u8, - low_bits_of_u64(i << 16 | i | (u64::from(CONTINUATION_BIT))) - ); - } - } - - // Examples from the DWARF 4 standard, section 7.6, figure 22. - #[test] - fn test_read_unsigned() { - let buf = [2u8]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 2, - read::unsigned(&mut readable).expect("Should read number") - ); - - let buf = [127u8]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 127, - read::unsigned(&mut readable).expect("Should read number") - ); - - let buf = [CONTINUATION_BIT, 1]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 128, - read::unsigned(&mut readable).expect("Should read number") - ); - - let buf = [1u8 | CONTINUATION_BIT, 1]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 129, - read::unsigned(&mut readable).expect("Should read number") - ); - - let buf = [2u8 | CONTINUATION_BIT, 1]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 130, - read::unsigned(&mut readable).expect("Should read number") - ); - - let buf = [57u8 | CONTINUATION_BIT, 100]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 12857, - read::unsigned(&mut readable).expect("Should read number") - ); - } - - // Examples from the DWARF 4 standard, section 7.6, figure 23. - #[test] - fn test_read_signed() { - let buf = [2u8]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!(2, read::signed(&mut readable).expect("Should read number")); - - let buf = [0x7eu8]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!(-2, read::signed(&mut readable).expect("Should read number")); - - let buf = [127u8 | CONTINUATION_BIT, 0]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 127, - read::signed(&mut readable).expect("Should read number") - ); - - let buf = [1u8 | CONTINUATION_BIT, 0x7f]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - -127, - read::signed(&mut readable).expect("Should read number") - ); - - let buf = [CONTINUATION_BIT, 1]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 128, - read::signed(&mut readable).expect("Should read number") - ); - - let buf = [CONTINUATION_BIT, 0x7f]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - -128, - read::signed(&mut readable).expect("Should read number") - ); - - let buf = [1u8 | CONTINUATION_BIT, 1]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - 129, - read::signed(&mut readable).expect("Should read number") - ); - - let buf = [0x7fu8 | CONTINUATION_BIT, 0x7e]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - -129, - read::signed(&mut readable).expect("Should read number") - ); - } - - #[test] - fn test_read_signed_63_bits() { - let buf = [ - CONTINUATION_BIT, - CONTINUATION_BIT, - CONTINUATION_BIT, - CONTINUATION_BIT, - CONTINUATION_BIT, - CONTINUATION_BIT, - CONTINUATION_BIT, - CONTINUATION_BIT, - 0x40, - ]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - -0x4000_0000_0000_0000, - read::signed(&mut readable).expect("Should read number") - ); - } - - #[test] - fn test_read_unsigned_not_enough_data() { - let buf = [CONTINUATION_BIT]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - read::unsigned(&mut readable).map_eof(&buf), - Err(Error::UnexpectedEof(ReaderOffsetId(1))) - ); - } - - #[test] - fn test_read_signed_not_enough_data() { - let buf = [CONTINUATION_BIT]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - read::signed(&mut readable).map_eof(&buf), - Err(Error::UnexpectedEof(ReaderOffsetId(1))) - ); - } - - #[test] - fn test_write_unsigned_not_enough_space() { - let mut buf = [0; 1]; - let mut writable = &mut buf[..]; - match write::unsigned(&mut writable, 128) { - Err(e) => assert_eq!(e.kind(), std::io::ErrorKind::WriteZero), - otherwise => panic!("Unexpected: {:?}", otherwise), - } - } - - #[test] - fn test_write_signed_not_enough_space() { - let mut buf = [0; 1]; - let mut writable = &mut buf[..]; - match write::signed(&mut writable, 128) { - Err(e) => assert_eq!(e.kind(), std::io::ErrorKind::WriteZero), - otherwise => panic!("Unexpected: {:?}", otherwise), - } - } - - #[test] - fn dogfood_signed() { - fn inner(i: i64) { - let mut buf = [0u8; 1024]; - - { - let mut writable = &mut buf[..]; - write::signed(&mut writable, i).expect("Should write signed number"); - } - - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - let result = read::signed(&mut readable).expect("Should be able to read it back again"); - assert_eq!(i, result); - } - for i in -513..513 { - inner(i); - } - inner(core::i64::MIN); - } - - #[test] - fn dogfood_unsigned() { - for i in 0..1025 { - let mut buf = [0u8; 1024]; - - { - let mut writable = &mut buf[..]; - write::unsigned(&mut writable, i).expect("Should write signed number"); - } - - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - let result = - read::unsigned(&mut readable).expect("Should be able to read it back again"); - assert_eq!(i, result); - } - } - - #[test] - fn test_read_unsigned_overflow() { - let buf = [ - 2u8 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 1, - ]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert!(read::unsigned(&mut readable).is_err()); - } - - #[test] - fn test_read_signed_overflow() { - let buf = [ - 2u8 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 2 | CONTINUATION_BIT, - 1, - ]; - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert!(read::signed(&mut readable).is_err()); - } - - #[test] - fn test_read_multiple() { - let buf = [2u8 | CONTINUATION_BIT, 1u8, 1u8]; - - let mut readable = EndianSlice::new(&buf[..], NativeEndian); - assert_eq!( - read::unsigned(&mut readable).expect("Should read first number"), - 130u64 - ); - assert_eq!( - read::unsigned(&mut readable).expect("Should read first number"), - 1u64 - ); - } - - #[test] - fn test_read_u16() { - for (buf, val) in [ - (&[2][..], 2), - (&[0x7f][..], 0x7f), - (&[0x80, 1][..], 0x80), - (&[0x81, 1][..], 0x81), - (&[0x82, 1][..], 0x82), - (&[0xff, 0x7f][..], 0x3fff), - (&[0x80, 0x80, 1][..], 0x4000), - (&[0xff, 0xff, 1][..], 0x7fff), - (&[0xff, 0xff, 3][..], 0xffff), - ] - .iter() - { - let mut readable = EndianSlice::new(buf, NativeEndian); - assert_eq!(*val, read::u16(&mut readable).expect("Should read number")); - } - - for buf in [ - &[0x80][..], - &[0x80, 0x80][..], - &[0x80, 0x80, 4][..], - &[0x80, 0x80, 0x80, 3][..], - ] - .iter() - { - let mut readable = EndianSlice::new(buf, NativeEndian); - assert!(read::u16(&mut readable).is_err(), "{:?}", buf); - } - } -} diff --git a/vendor/gimli/src/lib.rs b/vendor/gimli/src/lib.rs deleted file mode 100644 index 5dea344..0000000 --- a/vendor/gimli/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! `gimli` is a library for reading and writing the -//! [DWARF debugging format](https://dwarfstd.org/). -//! -//! See the [read](./read/index.html) and [write](./write/index.html) modules -//! for examples and API documentation. -//! -//! ## Cargo Features -//! -//! Cargo features that can be enabled with `gimli`: -//! -//! * `std`: Enabled by default. Use the `std` library. Disabling this feature -//! allows using `gimli` in embedded environments that do not have access to -//! `std`. Note that even when `std` is disabled, `gimli` still requires an -//! implementation of the `alloc` crate. -//! -//! * `read`: Enabled by default. Enables the `read` module. Use of `std` is -//! optional. -//! -//! * `write`: Enabled by default. Enables the `write` module. Always uses -//! the `std` library. -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] -// Selectively enable rust 2018 warnings -#![warn(bare_trait_objects)] -#![warn(unused_extern_crates)] -#![warn(ellipsis_inclusive_range_patterns)] -//#![warn(elided_lifetimes_in_paths)] -#![warn(explicit_outlives_requirements)] -// Style. -#![allow(clippy::bool_to_int_with_if)] -#![allow(clippy::collapsible_else_if)] -#![allow(clippy::comparison_chain)] -#![allow(clippy::manual_range_contains)] -#![allow(clippy::needless_late_init)] -#![allow(clippy::too_many_arguments)] -// False positives with `fallible_iterator`. -#![allow(clippy::should_implement_trait)] -// False positives. -#![allow(clippy::derive_partial_eq_without_eq)] -#![no_std] - -#[allow(unused_imports)] -#[cfg(any(feature = "read", feature = "write"))] -#[macro_use] -extern crate alloc; - -#[cfg(any(feature = "std", feature = "write"))] -#[macro_use] -extern crate std; - -#[cfg(feature = "endian-reader")] -pub use stable_deref_trait::{CloneStableDeref, StableDeref}; - -mod common; -pub use crate::common::*; - -mod arch; -pub use crate::arch::*; - -pub mod constants; -// For backwards compat. -pub use crate::constants::*; - -mod endianity; -pub use crate::endianity::*; - -pub mod leb128; - -#[cfg(feature = "read-core")] -pub mod read; -// For backwards compat. -#[cfg(feature = "read-core")] -pub use crate::read::*; - -#[cfg(feature = "write")] -pub mod write; - -#[cfg(test)] -mod test_util; diff --git a/vendor/gimli/src/read/abbrev.rs b/vendor/gimli/src/read/abbrev.rs deleted file mode 100644 index 1162583..0000000 --- a/vendor/gimli/src/read/abbrev.rs +++ /dev/null @@ -1,1102 +0,0 @@ -//! Functions for parsing DWARF debugging abbreviations. - -use alloc::collections::btree_map; -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::convert::TryFrom; -use core::fmt::{self, Debug}; -use core::iter::FromIterator; -use core::ops::Deref; - -use crate::common::{DebugAbbrevOffset, Encoding, SectionId}; -use crate::constants; -use crate::endianity::Endianity; -use crate::read::{ - DebugInfoUnitHeadersIter, EndianSlice, Error, Reader, ReaderOffset, Result, Section, UnitHeader, -}; - -/// The `DebugAbbrev` struct represents the abbreviations describing -/// `DebuggingInformationEntry`s' attribute names and forms found in the -/// `.debug_abbrev` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugAbbrev<R> { - debug_abbrev_section: R, -} - -impl<'input, Endian> DebugAbbrev<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugAbbrev` instance from the data in the `.debug_abbrev` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_abbrev` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugAbbrev, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_abbrev_section_somehow = || &buf; - /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); - /// ``` - pub fn new(debug_abbrev_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_abbrev_section, endian)) - } -} - -impl<R: Reader> DebugAbbrev<R> { - /// Parse the abbreviations at the given `offset` within this - /// `.debug_abbrev` section. - /// - /// The `offset` should generally be retrieved from a unit header. - pub fn abbreviations( - &self, - debug_abbrev_offset: DebugAbbrevOffset<R::Offset>, - ) -> Result<Abbreviations> { - let input = &mut self.debug_abbrev_section.clone(); - input.skip(debug_abbrev_offset.0)?; - Abbreviations::parse(input) - } -} - -impl<T> DebugAbbrev<T> { - /// Create a `DebugAbbrev` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugAbbrev<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAbbrev<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.debug_abbrev_section).into() - } -} - -impl<R> Section<R> for DebugAbbrev<R> { - fn id() -> SectionId { - SectionId::DebugAbbrev - } - - fn reader(&self) -> &R { - &self.debug_abbrev_section - } -} - -impl<R> From<R> for DebugAbbrev<R> { - fn from(debug_abbrev_section: R) -> Self { - DebugAbbrev { - debug_abbrev_section, - } - } -} - -/// The strategy to use for caching abbreviations. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[non_exhaustive] -pub enum AbbreviationsCacheStrategy { - /// Cache abbreviations that are used more than once. - /// - /// This is useful if the units in the `.debug_info` section will be parsed only once. - Duplicates, - /// Cache all abbreviations. - /// - /// This is useful if the units in the `.debug_info` section will be parsed more than once. - All, -} - -/// A cache of previously parsed `Abbreviations`. -#[derive(Debug, Default)] -pub struct AbbreviationsCache { - abbreviations: btree_map::BTreeMap<u64, Result<Arc<Abbreviations>>>, -} - -impl AbbreviationsCache { - /// Create an empty abbreviations cache. - pub fn new() -> Self { - Self::default() - } - - /// Parse abbreviations and store them in the cache. - /// - /// This will iterate over the given units to determine the abbreviations - /// offsets. Any existing cache entries are discarded. - /// - /// Errors during parsing abbreviations are also stored in the cache. - /// Errors during iterating over the units are ignored. - pub fn populate<R: Reader>( - &mut self, - strategy: AbbreviationsCacheStrategy, - debug_abbrev: &DebugAbbrev<R>, - mut units: DebugInfoUnitHeadersIter<R>, - ) { - let mut offsets = Vec::new(); - match strategy { - AbbreviationsCacheStrategy::Duplicates => { - while let Ok(Some(unit)) = units.next() { - offsets.push(unit.debug_abbrev_offset()); - } - offsets.sort_unstable_by_key(|offset| offset.0); - let mut prev_offset = R::Offset::from_u8(0); - let mut count = 0; - offsets.retain(|offset| { - if count == 0 || prev_offset != offset.0 { - prev_offset = offset.0; - count = 1; - } else { - count += 1; - } - count == 2 - }); - } - AbbreviationsCacheStrategy::All => { - while let Ok(Some(unit)) = units.next() { - offsets.push(unit.debug_abbrev_offset()); - } - offsets.sort_unstable_by_key(|offset| offset.0); - offsets.dedup(); - } - } - self.abbreviations = offsets - .into_iter() - .map(|offset| { - ( - offset.0.into_u64(), - debug_abbrev.abbreviations(offset).map(Arc::new), - ) - }) - .collect(); - } - - /// Set an entry in the abbreviations cache. - /// - /// This is only required if you want to manually populate the cache. - pub fn set<R: Reader>( - &mut self, - offset: DebugAbbrevOffset<R::Offset>, - abbreviations: Arc<Abbreviations>, - ) { - self.abbreviations - .insert(offset.0.into_u64(), Ok(abbreviations)); - } - - /// Parse the abbreviations at the given offset. - /// - /// This uses the cache if possible, but does not update it. - pub fn get<R: Reader>( - &self, - debug_abbrev: &DebugAbbrev<R>, - offset: DebugAbbrevOffset<R::Offset>, - ) -> Result<Arc<Abbreviations>> { - match self.abbreviations.get(&offset.0.into_u64()) { - Some(entry) => entry.clone(), - None => debug_abbrev.abbreviations(offset).map(Arc::new), - } - } -} - -/// A set of type abbreviations. -/// -/// Construct an `Abbreviations` instance with the -/// [`abbreviations()`](struct.UnitHeader.html#method.abbreviations) -/// method. -#[derive(Debug, Default, Clone)] -pub struct Abbreviations { - vec: Vec<Abbreviation>, - map: btree_map::BTreeMap<u64, Abbreviation>, -} - -impl Abbreviations { - /// Construct a new, empty set of abbreviations. - fn empty() -> Abbreviations { - Abbreviations { - vec: Vec::new(), - map: btree_map::BTreeMap::new(), - } - } - - /// Insert an abbreviation into the set. - /// - /// Returns `Ok` if it is the first abbreviation in the set with its code, - /// `Err` if the code is a duplicate and there already exists an - /// abbreviation in the set with the given abbreviation's code. - fn insert(&mut self, abbrev: Abbreviation) -> ::core::result::Result<(), ()> { - let code_usize = abbrev.code as usize; - if code_usize as u64 == abbrev.code { - // Optimize for sequential abbreviation codes by storing them - // in a Vec, as long as the map doesn't already contain them. - // A potential further optimization would be to allow some - // holes in the Vec, but there's no need for that yet. - if code_usize - 1 < self.vec.len() { - return Err(()); - } else if code_usize - 1 == self.vec.len() { - if !self.map.is_empty() && self.map.contains_key(&abbrev.code) { - return Err(()); - } else { - self.vec.push(abbrev); - return Ok(()); - } - } - } - match self.map.entry(abbrev.code) { - btree_map::Entry::Occupied(_) => Err(()), - btree_map::Entry::Vacant(entry) => { - entry.insert(abbrev); - Ok(()) - } - } - } - - /// Get the abbreviation associated with the given code. - #[inline] - pub fn get(&self, code: u64) -> Option<&Abbreviation> { - if let Ok(code) = usize::try_from(code) { - let index = code.checked_sub(1)?; - if index < self.vec.len() { - return Some(&self.vec[index]); - } - } - - self.map.get(&code) - } - - /// Parse a series of abbreviations, terminated by a null abbreviation. - fn parse<R: Reader>(input: &mut R) -> Result<Abbreviations> { - let mut abbrevs = Abbreviations::empty(); - - while let Some(abbrev) = Abbreviation::parse(input)? { - if abbrevs.insert(abbrev).is_err() { - return Err(Error::DuplicateAbbreviationCode); - } - } - - Ok(abbrevs) - } -} - -/// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: -/// its code, tag type, whether it has children, and its set of attributes. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Abbreviation { - code: u64, - tag: constants::DwTag, - has_children: constants::DwChildren, - attributes: Attributes, -} - -impl Abbreviation { - /// Construct a new `Abbreviation`. - /// - /// ### Panics - /// - /// Panics if `code` is `0`. - pub(crate) fn new( - code: u64, - tag: constants::DwTag, - has_children: constants::DwChildren, - attributes: Attributes, - ) -> Abbreviation { - assert_ne!(code, 0); - Abbreviation { - code, - tag, - has_children, - attributes, - } - } - - /// Get this abbreviation's code. - #[inline] - pub fn code(&self) -> u64 { - self.code - } - - /// Get this abbreviation's tag. - #[inline] - pub fn tag(&self) -> constants::DwTag { - self.tag - } - - /// Return true if this abbreviation's type has children, false otherwise. - #[inline] - pub fn has_children(&self) -> bool { - self.has_children == constants::DW_CHILDREN_yes - } - - /// Get this abbreviation's attributes. - #[inline] - pub fn attributes(&self) -> &[AttributeSpecification] { - &self.attributes[..] - } - - /// Parse an abbreviation's tag. - fn parse_tag<R: Reader>(input: &mut R) -> Result<constants::DwTag> { - let val = input.read_uleb128_u16()?; - if val == 0 { - Err(Error::AbbreviationTagZero) - } else { - Ok(constants::DwTag(val)) - } - } - - /// Parse an abbreviation's "does the type have children?" byte. - fn parse_has_children<R: Reader>(input: &mut R) -> Result<constants::DwChildren> { - let val = input.read_u8()?; - let val = constants::DwChildren(val); - if val == constants::DW_CHILDREN_no || val == constants::DW_CHILDREN_yes { - Ok(val) - } else { - Err(Error::BadHasChildren) - } - } - - /// Parse a series of attribute specifications, terminated by a null attribute - /// specification. - fn parse_attributes<R: Reader>(input: &mut R) -> Result<Attributes> { - let mut attrs = Attributes::new(); - - while let Some(attr) = AttributeSpecification::parse(input)? { - attrs.push(attr); - } - - Ok(attrs) - } - - /// Parse an abbreviation. Return `None` for the null abbreviation, `Some` - /// for an actual abbreviation. - fn parse<R: Reader>(input: &mut R) -> Result<Option<Abbreviation>> { - let code = input.read_uleb128()?; - if code == 0 { - return Ok(None); - } - - let tag = Self::parse_tag(input)?; - let has_children = Self::parse_has_children(input)?; - let attributes = Self::parse_attributes(input)?; - let abbrev = Abbreviation::new(code, tag, has_children, attributes); - Ok(Some(abbrev)) - } -} - -/// A list of attributes found in an `Abbreviation` -#[derive(Clone)] -pub(crate) enum Attributes { - Inline { - buf: [AttributeSpecification; MAX_ATTRIBUTES_INLINE], - len: usize, - }, - Heap(Vec<AttributeSpecification>), -} - -// Length of 5 based on benchmark results for both x86-64 and i686. -const MAX_ATTRIBUTES_INLINE: usize = 5; - -impl Attributes { - /// Returns a new empty list of attributes - fn new() -> Attributes { - let default = - AttributeSpecification::new(constants::DW_AT_null, constants::DW_FORM_null, None); - Attributes::Inline { - buf: [default; 5], - len: 0, - } - } - - /// Pushes a new value onto this list of attributes. - fn push(&mut self, attr: AttributeSpecification) { - match self { - Attributes::Heap(list) => list.push(attr), - Attributes::Inline { - buf, - len: MAX_ATTRIBUTES_INLINE, - } => { - let mut list = buf.to_vec(); - list.push(attr); - *self = Attributes::Heap(list); - } - Attributes::Inline { buf, len } => { - buf[*len] = attr; - *len += 1; - } - } - } -} - -impl Debug for Attributes { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -impl PartialEq for Attributes { - fn eq(&self, other: &Attributes) -> bool { - **self == **other - } -} - -impl Eq for Attributes {} - -impl Deref for Attributes { - type Target = [AttributeSpecification]; - fn deref(&self) -> &[AttributeSpecification] { - match self { - Attributes::Inline { buf, len } => &buf[..*len], - Attributes::Heap(list) => list, - } - } -} - -impl FromIterator<AttributeSpecification> for Attributes { - fn from_iter<I>(iter: I) -> Attributes - where - I: IntoIterator<Item = AttributeSpecification>, - { - let mut list = Attributes::new(); - for item in iter { - list.push(item); - } - list - } -} - -impl From<Vec<AttributeSpecification>> for Attributes { - fn from(list: Vec<AttributeSpecification>) -> Attributes { - Attributes::Heap(list) - } -} - -/// The description of an attribute in an abbreviated type. It is a pair of name -/// and form. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AttributeSpecification { - name: constants::DwAt, - form: constants::DwForm, - implicit_const_value: i64, -} - -impl AttributeSpecification { - /// Construct a new `AttributeSpecification` from the given name and form - /// and implicit const value. - #[inline] - pub fn new( - name: constants::DwAt, - form: constants::DwForm, - implicit_const_value: Option<i64>, - ) -> AttributeSpecification { - debug_assert!( - (form == constants::DW_FORM_implicit_const && implicit_const_value.is_some()) - || (form != constants::DW_FORM_implicit_const && implicit_const_value.is_none()) - ); - AttributeSpecification { - name, - form, - implicit_const_value: implicit_const_value.unwrap_or(0), - } - } - - /// Get the attribute's name. - #[inline] - pub fn name(&self) -> constants::DwAt { - self.name - } - - /// Get the attribute's form. - #[inline] - pub fn form(&self) -> constants::DwForm { - self.form - } - - /// Get the attribute's implicit const value. - #[inline] - pub fn implicit_const_value(&self) -> Option<i64> { - if self.form == constants::DW_FORM_implicit_const { - Some(self.implicit_const_value) - } else { - None - } - } - - /// Return the size of the attribute, in bytes. - /// - /// Note that because some attributes are variably sized, the size cannot - /// always be known without parsing, in which case we return `None`. - pub fn size<R: Reader>(&self, header: &UnitHeader<R>) -> Option<usize> { - get_attribute_size(self.form, header.encoding()).map(usize::from) - } - - /// Parse an attribute's form. - fn parse_form<R: Reader>(input: &mut R) -> Result<constants::DwForm> { - let val = input.read_uleb128_u16()?; - if val == 0 { - Err(Error::AttributeFormZero) - } else { - Ok(constants::DwForm(val)) - } - } - - /// Parse an attribute specification. Returns `None` for the null attribute - /// specification, `Some` for an actual attribute specification. - fn parse<R: Reader>(input: &mut R) -> Result<Option<AttributeSpecification>> { - let name = input.read_uleb128_u16()?; - if name == 0 { - // Parse the null attribute specification. - let form = input.read_uleb128_u16()?; - return if form == 0 { - Ok(None) - } else { - Err(Error::ExpectedZero) - }; - } - - let name = constants::DwAt(name); - let form = Self::parse_form(input)?; - let implicit_const_value = if form == constants::DW_FORM_implicit_const { - Some(input.read_sleb128()?) - } else { - None - }; - let spec = AttributeSpecification::new(name, form, implicit_const_value); - Ok(Some(spec)) - } -} - -#[inline] -pub(crate) fn get_attribute_size(form: constants::DwForm, encoding: Encoding) -> Option<u8> { - match form { - constants::DW_FORM_addr => Some(encoding.address_size), - - constants::DW_FORM_implicit_const | constants::DW_FORM_flag_present => Some(0), - - constants::DW_FORM_data1 - | constants::DW_FORM_flag - | constants::DW_FORM_strx1 - | constants::DW_FORM_ref1 - | constants::DW_FORM_addrx1 => Some(1), - - constants::DW_FORM_data2 - | constants::DW_FORM_ref2 - | constants::DW_FORM_addrx2 - | constants::DW_FORM_strx2 => Some(2), - - constants::DW_FORM_addrx3 | constants::DW_FORM_strx3 => Some(3), - - constants::DW_FORM_data4 - | constants::DW_FORM_ref_sup4 - | constants::DW_FORM_ref4 - | constants::DW_FORM_strx4 - | constants::DW_FORM_addrx4 => Some(4), - - constants::DW_FORM_data8 - | constants::DW_FORM_ref8 - | constants::DW_FORM_ref_sig8 - | constants::DW_FORM_ref_sup8 => Some(8), - - constants::DW_FORM_data16 => Some(16), - - constants::DW_FORM_sec_offset - | constants::DW_FORM_GNU_ref_alt - | constants::DW_FORM_strp - | constants::DW_FORM_strp_sup - | constants::DW_FORM_GNU_strp_alt - | constants::DW_FORM_line_strp => Some(encoding.format.word_size()), - - constants::DW_FORM_ref_addr => { - // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr - // has the same size as an address on the target system. This was changed - // in DWARF version 3. - Some(if encoding.version == 2 { - encoding.address_size - } else { - encoding.format.word_size() - }) - } - - // Variably sized forms. - constants::DW_FORM_block - | constants::DW_FORM_block1 - | constants::DW_FORM_block2 - | constants::DW_FORM_block4 - | constants::DW_FORM_exprloc - | constants::DW_FORM_ref_udata - | constants::DW_FORM_string - | constants::DW_FORM_sdata - | constants::DW_FORM_udata - | constants::DW_FORM_indirect => None, - - // We don't know the size of unknown forms. - _ => None, - } -} - -#[cfg(test)] -pub mod tests { - use super::*; - use crate::constants; - use crate::endianity::LittleEndian; - use crate::read::{EndianSlice, Error}; - use crate::test_util::GimliSectionMethods; - #[cfg(target_pointer_width = "32")] - use core::u32; - use test_assembler::Section; - - pub trait AbbrevSectionMethods { - fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self; - fn abbrev_null(self) -> Self; - fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self; - fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self; - fn abbrev_attr_null(self) -> Self; - } - - impl AbbrevSectionMethods for Section { - fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self { - self.uleb(code).uleb(tag.0.into()).D8(children.0) - } - - fn abbrev_null(self) -> Self { - self.D8(0) - } - - fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self { - self.uleb(name.0.into()).uleb(form.0.into()) - } - - fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self { - self.uleb(name.0.into()) - .uleb(constants::DW_FORM_implicit_const.0.into()) - .sleb(value) - } - - fn abbrev_attr_null(self) -> Self { - self.D8(0).D8(0) - } - } - - #[test] - fn test_debug_abbrev_ok() { - let extra_start = [1, 2, 3, 4]; - let expected_rest = [5, 6, 7, 8]; - #[rustfmt::skip] - let buf = Section::new() - .append_bytes(&extra_start) - .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) - .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) - .abbrev_attr_null() - .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) - .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) - .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) - .abbrev_attr_null() - .abbrev_null() - .append_bytes(&expected_rest) - .get_contents() - .unwrap(); - - let abbrev1 = Abbreviation::new( - 1, - constants::DW_TAG_compile_unit, - constants::DW_CHILDREN_yes, - vec![ - AttributeSpecification::new( - constants::DW_AT_producer, - constants::DW_FORM_strp, - None, - ), - AttributeSpecification::new( - constants::DW_AT_language, - constants::DW_FORM_data2, - None, - ), - ] - .into(), - ); - - let abbrev2 = Abbreviation::new( - 2, - constants::DW_TAG_subprogram, - constants::DW_CHILDREN_no, - vec![AttributeSpecification::new( - constants::DW_AT_name, - constants::DW_FORM_string, - None, - )] - .into(), - ); - - let debug_abbrev = DebugAbbrev::new(&buf, LittleEndian); - let debug_abbrev_offset = DebugAbbrevOffset(extra_start.len()); - let abbrevs = debug_abbrev - .abbreviations(debug_abbrev_offset) - .expect("Should parse abbreviations"); - assert_eq!(abbrevs.get(1), Some(&abbrev1)); - assert_eq!(abbrevs.get(2), Some(&abbrev2)); - } - - #[test] - fn test_abbreviations_insert() { - fn abbrev(code: u16) -> Abbreviation { - Abbreviation::new( - code.into(), - constants::DwTag(code), - constants::DW_CHILDREN_no, - vec![].into(), - ) - } - - fn assert_abbrev(abbrevs: &Abbreviations, code: u16) { - let abbrev = abbrevs.get(code.into()).unwrap(); - assert_eq!(abbrev.tag(), constants::DwTag(code)); - } - - // Sequential insert. - let mut abbrevs = Abbreviations::empty(); - abbrevs.insert(abbrev(1)).unwrap(); - abbrevs.insert(abbrev(2)).unwrap(); - assert_eq!(abbrevs.vec.len(), 2); - assert!(abbrevs.map.is_empty()); - assert_abbrev(&abbrevs, 1); - assert_abbrev(&abbrevs, 2); - - // Out of order insert. - let mut abbrevs = Abbreviations::empty(); - abbrevs.insert(abbrev(2)).unwrap(); - abbrevs.insert(abbrev(3)).unwrap(); - assert!(abbrevs.vec.is_empty()); - assert_abbrev(&abbrevs, 2); - assert_abbrev(&abbrevs, 3); - - // Mixed order insert. - let mut abbrevs = Abbreviations::empty(); - abbrevs.insert(abbrev(1)).unwrap(); - abbrevs.insert(abbrev(3)).unwrap(); - abbrevs.insert(abbrev(2)).unwrap(); - assert_eq!(abbrevs.vec.len(), 2); - assert_abbrev(&abbrevs, 1); - assert_abbrev(&abbrevs, 2); - assert_abbrev(&abbrevs, 3); - - // Duplicate code in vec. - let mut abbrevs = Abbreviations::empty(); - abbrevs.insert(abbrev(1)).unwrap(); - abbrevs.insert(abbrev(2)).unwrap(); - assert_eq!(abbrevs.insert(abbrev(1)), Err(())); - assert_eq!(abbrevs.insert(abbrev(2)), Err(())); - - // Duplicate code in map when adding to map. - let mut abbrevs = Abbreviations::empty(); - abbrevs.insert(abbrev(2)).unwrap(); - assert_eq!(abbrevs.insert(abbrev(2)), Err(())); - - // Duplicate code in map when adding to vec. - let mut abbrevs = Abbreviations::empty(); - abbrevs.insert(abbrev(2)).unwrap(); - abbrevs.insert(abbrev(1)).unwrap(); - assert_eq!(abbrevs.insert(abbrev(2)), Err(())); - - // 32-bit usize conversions. - let mut abbrevs = Abbreviations::empty(); - abbrevs.insert(abbrev(2)).unwrap(); - } - - #[test] - #[cfg(target_pointer_width = "32")] - fn test_abbreviations_insert_32() { - fn abbrev(code: u64) -> Abbreviation { - Abbreviation::new( - code, - constants::DwTag(code as u16), - constants::DW_CHILDREN_no, - vec![].into(), - ) - } - - fn assert_abbrev(abbrevs: &Abbreviations, code: u64) { - let abbrev = abbrevs.get(code).unwrap(); - assert_eq!(abbrev.tag(), constants::DwTag(code as u16)); - } - - let mut abbrevs = Abbreviations::empty(); - abbrevs.insert(abbrev(1)).unwrap(); - - let wrap_code = (u32::MAX as u64 + 1) + 1; - // `get` should not treat the wrapped code as `1`. - assert_eq!(abbrevs.get(wrap_code), None); - // `insert` should not treat the wrapped code as `1`. - abbrevs.insert(abbrev(wrap_code)).unwrap(); - assert_abbrev(&abbrevs, 1); - assert_abbrev(&abbrevs, wrap_code); - } - - #[test] - fn test_parse_abbreviations_ok() { - let expected_rest = [1, 2, 3, 4]; - #[rustfmt::skip] - let buf = Section::new() - .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) - .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) - .abbrev_attr_null() - .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) - .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) - .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) - .abbrev_attr_null() - .abbrev_null() - .append_bytes(&expected_rest) - .get_contents() - .unwrap(); - let rest = &mut EndianSlice::new(&*buf, LittleEndian); - - let abbrev1 = Abbreviation::new( - 1, - constants::DW_TAG_compile_unit, - constants::DW_CHILDREN_yes, - vec![ - AttributeSpecification::new( - constants::DW_AT_producer, - constants::DW_FORM_strp, - None, - ), - AttributeSpecification::new( - constants::DW_AT_language, - constants::DW_FORM_data2, - None, - ), - ] - .into(), - ); - - let abbrev2 = Abbreviation::new( - 2, - constants::DW_TAG_subprogram, - constants::DW_CHILDREN_no, - vec![AttributeSpecification::new( - constants::DW_AT_name, - constants::DW_FORM_string, - None, - )] - .into(), - ); - - let abbrevs = Abbreviations::parse(rest).expect("Should parse abbreviations"); - assert_eq!(abbrevs.get(1), Some(&abbrev1)); - assert_eq!(abbrevs.get(2), Some(&abbrev2)); - assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_abbreviations_duplicate() { - let expected_rest = [1, 2, 3, 4]; - #[rustfmt::skip] - let buf = Section::new() - .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) - .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) - .abbrev_attr_null() - .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) - .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) - .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) - .abbrev_attr_null() - .abbrev_null() - .append_bytes(&expected_rest) - .get_contents() - .unwrap(); - let buf = &mut EndianSlice::new(&*buf, LittleEndian); - - match Abbreviations::parse(buf) { - Err(Error::DuplicateAbbreviationCode) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_abbreviation_tag_ok() { - let buf = [0x01, 0x02]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let tag = Abbreviation::parse_tag(rest).expect("Should parse tag"); - assert_eq!(tag, constants::DW_TAG_array_type); - assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); - } - - #[test] - fn test_parse_abbreviation_tag_zero() { - let buf = [0x00]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - match Abbreviation::parse_tag(buf) { - Err(Error::AbbreviationTagZero) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_abbreviation_has_children() { - let buf = [0x00, 0x01, 0x02]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); - assert_eq!(val, constants::DW_CHILDREN_no); - let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); - assert_eq!(val, constants::DW_CHILDREN_yes); - match Abbreviation::parse_has_children(rest) { - Err(Error::BadHasChildren) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_abbreviation_ok() { - let expected_rest = [0x01, 0x02, 0x03, 0x04]; - let buf = Section::new() - .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) - .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) - .abbrev_attr_null() - .append_bytes(&expected_rest) - .get_contents() - .unwrap(); - let rest = &mut EndianSlice::new(&*buf, LittleEndian); - - let expect = Some(Abbreviation::new( - 1, - constants::DW_TAG_subprogram, - constants::DW_CHILDREN_no, - vec![AttributeSpecification::new( - constants::DW_AT_name, - constants::DW_FORM_string, - None, - )] - .into(), - )); - - let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); - assert_eq!(abbrev, expect); - assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_abbreviation_implicit_const_ok() { - let expected_rest = [0x01, 0x02, 0x03, 0x04]; - let buf = Section::new() - .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) - .abbrev_attr_implicit_const(constants::DW_AT_name, -42) - .abbrev_attr_null() - .append_bytes(&expected_rest) - .get_contents() - .unwrap(); - let rest = &mut EndianSlice::new(&*buf, LittleEndian); - - let expect = Some(Abbreviation::new( - 1, - constants::DW_TAG_subprogram, - constants::DW_CHILDREN_no, - vec![AttributeSpecification::new( - constants::DW_AT_name, - constants::DW_FORM_implicit_const, - Some(-42), - )] - .into(), - )); - - let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); - assert_eq!(abbrev, expect); - assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_abbreviation_implicit_const_no_const() { - let buf = Section::new() - .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) - .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_implicit_const) - .get_contents() - .unwrap(); - let buf = &mut EndianSlice::new(&*buf, LittleEndian); - - match Abbreviation::parse(buf) { - Err(Error::UnexpectedEof(_)) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - fn test_parse_null_abbreviation_ok() { - let expected_rest = [0x01, 0x02, 0x03, 0x04]; - let buf = Section::new() - .abbrev_null() - .append_bytes(&expected_rest) - .get_contents() - .unwrap(); - let rest = &mut EndianSlice::new(&*buf, LittleEndian); - - let abbrev = Abbreviation::parse(rest).expect("Should parse null abbreviation"); - assert!(abbrev.is_none()); - assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_attribute_form_ok() { - let buf = [0x01, 0x02]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let tag = AttributeSpecification::parse_form(rest).expect("Should parse form"); - assert_eq!(tag, constants::DW_FORM_addr); - assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); - } - - #[test] - fn test_parse_attribute_form_zero() { - let buf = [0x00]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - match AttributeSpecification::parse_form(buf) { - Err(Error::AttributeFormZero) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_null_attribute_specification_ok() { - let buf = [0x00, 0x00, 0x01]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let attr = - AttributeSpecification::parse(rest).expect("Should parse null attribute specification"); - assert!(attr.is_none()); - assert_eq!(*rest, EndianSlice::new(&buf[2..], LittleEndian)); - } - - #[test] - fn test_parse_attribute_specifications_name_zero() { - let buf = [0x00, 0x01, 0x00, 0x00]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - match AttributeSpecification::parse(buf) { - Err(Error::ExpectedZero) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_attribute_specifications_form_zero() { - let buf = [0x01, 0x00, 0x00, 0x00]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - match AttributeSpecification::parse(buf) { - Err(Error::AttributeFormZero) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_get_abbrev_zero() { - let mut abbrevs = Abbreviations::empty(); - abbrevs - .insert(Abbreviation::new( - 1, - constants::DwTag(1), - constants::DW_CHILDREN_no, - vec![].into(), - )) - .unwrap(); - assert!(abbrevs.get(0).is_none()); - } -} diff --git a/vendor/gimli/src/read/addr.rs b/vendor/gimli/src/read/addr.rs deleted file mode 100644 index 593f9fe..0000000 --- a/vendor/gimli/src/read/addr.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::common::{DebugAddrBase, DebugAddrIndex, SectionId}; -use crate::read::{Reader, ReaderOffset, Result, Section}; - -/// The raw contents of the `.debug_addr` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugAddr<R> { - section: R, -} - -impl<R: Reader> DebugAddr<R> { - // TODO: add an iterator over the sets of addresses in the section. - // This is not needed for common usage of the section though. - - /// Returns the address at the given `base` and `index`. - /// - /// A set of addresses in the `.debug_addr` section consists of a header - /// followed by a series of addresses. - /// - /// The `base` must be the `DW_AT_addr_base` value from the compilation unit DIE. - /// This is an offset that points to the first address following the header. - /// - /// The `index` is the value of a `DW_FORM_addrx` attribute. - /// - /// The `address_size` must be the size of the address for the compilation unit. - /// This value must also match the header. However, note that we do not parse the - /// header to validate this, since locating the header is unreliable, and the GNU - /// extensions do not emit it. - pub fn get_address( - &self, - address_size: u8, - base: DebugAddrBase<R::Offset>, - index: DebugAddrIndex<R::Offset>, - ) -> Result<u64> { - let input = &mut self.section.clone(); - input.skip(base.0)?; - input.skip(R::Offset::from_u64( - index.0.into_u64() * u64::from(address_size), - )?)?; - input.read_address(address_size) - } -} - -impl<T> DebugAddr<T> { - /// Create a `DebugAddr` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugAddr<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAddr<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.section).into() - } -} - -impl<R> Section<R> for DebugAddr<R> { - fn id() -> SectionId { - SectionId::DebugAddr - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugAddr<R> { - fn from(section: R) -> Self { - DebugAddr { section } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::read::EndianSlice; - use crate::test_util::GimliSectionMethods; - use crate::{Format, LittleEndian}; - use test_assembler::{Endian, Label, LabelMaker, Section}; - - #[test] - fn test_get_address() { - for format in vec![Format::Dwarf32, Format::Dwarf64] { - for address_size in vec![4, 8] { - let zero = Label::new(); - let length = Label::new(); - let start = Label::new(); - let first = Label::new(); - let end = Label::new(); - let mut section = Section::with_endian(Endian::Little) - .mark(&zero) - .initial_length(format, &length, &start) - .D16(5) - .D8(address_size) - .D8(0) - .mark(&first); - for i in 0..20 { - section = section.word(address_size, 1000 + i); - } - section = section.mark(&end); - length.set_const((&end - &start) as u64); - - let section = section.get_contents().unwrap(); - let debug_addr = DebugAddr::from(EndianSlice::new(§ion, LittleEndian)); - let base = DebugAddrBase((&first - &zero) as usize); - - assert_eq!( - debug_addr.get_address(address_size, base, DebugAddrIndex(0)), - Ok(1000) - ); - assert_eq!( - debug_addr.get_address(address_size, base, DebugAddrIndex(19)), - Ok(1019) - ); - } - } - } -} diff --git a/vendor/gimli/src/read/aranges.rs b/vendor/gimli/src/read/aranges.rs deleted file mode 100644 index 83159b6..0000000 --- a/vendor/gimli/src/read/aranges.rs +++ /dev/null @@ -1,660 +0,0 @@ -use crate::common::{DebugArangesOffset, DebugInfoOffset, Encoding, SectionId}; -use crate::endianity::Endianity; -use crate::read::{EndianSlice, Error, Range, Reader, ReaderOffset, Result, Section}; - -/// The `DebugAranges` struct represents the DWARF address range information -/// found in the `.debug_aranges` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugAranges<R> { - section: R, -} - -impl<'input, Endian> DebugAranges<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugAranges` instance from the data in the `.debug_aranges` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_aranges` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugAranges, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_aranges_section = || &buf; - /// let debug_aranges = - /// DebugAranges::new(read_debug_aranges_section(), LittleEndian); - /// ``` - pub fn new(section: &'input [u8], endian: Endian) -> Self { - DebugAranges { - section: EndianSlice::new(section, endian), - } - } -} - -impl<R: Reader> DebugAranges<R> { - /// Iterate the sets of entries in the `.debug_aranges` section. - /// - /// Each set of entries belongs to a single unit. - pub fn headers(&self) -> ArangeHeaderIter<R> { - ArangeHeaderIter { - input: self.section.clone(), - offset: DebugArangesOffset(R::Offset::from_u8(0)), - } - } - - /// Get the header at the given offset. - pub fn header(&self, offset: DebugArangesOffset<R::Offset>) -> Result<ArangeHeader<R>> { - let mut input = self.section.clone(); - input.skip(offset.0)?; - ArangeHeader::parse(&mut input, offset) - } -} - -impl<T> DebugAranges<T> { - /// Create a `DebugAranges` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugAranges<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAranges<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.section).into() - } -} - -impl<R> Section<R> for DebugAranges<R> { - fn id() -> SectionId { - SectionId::DebugAranges - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugAranges<R> { - fn from(section: R) -> Self { - DebugAranges { section } - } -} - -/// An iterator over the headers of a `.debug_aranges` section. -#[derive(Clone, Debug)] -pub struct ArangeHeaderIter<R: Reader> { - input: R, - offset: DebugArangesOffset<R::Offset>, -} - -impl<R: Reader> ArangeHeaderIter<R> { - /// Advance the iterator to the next header. - pub fn next(&mut self) -> Result<Option<ArangeHeader<R>>> { - if self.input.is_empty() { - return Ok(None); - } - - let len = self.input.len(); - match ArangeHeader::parse(&mut self.input, self.offset) { - Ok(header) => { - self.offset.0 += len - self.input.len(); - Ok(Some(header)) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for ArangeHeaderIter<R> { - type Item = ArangeHeader<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - ArangeHeaderIter::next(self) - } -} - -/// A header for a set of entries in the `.debug_arange` section. -/// -/// These entries all belong to a single unit. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ArangeHeader<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - offset: DebugArangesOffset<Offset>, - encoding: Encoding, - length: Offset, - debug_info_offset: DebugInfoOffset<Offset>, - segment_size: u8, - entries: R, -} - -impl<R, Offset> ArangeHeader<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - fn parse(input: &mut R, offset: DebugArangesOffset<Offset>) -> Result<Self> { - let (length, format) = input.read_initial_length()?; - let mut rest = input.split(length)?; - - // Check the version. The DWARF 5 spec says that this is always 2, but version 3 - // has been observed in the wild, potentially due to a bug; see - // https://github.com/gimli-rs/gimli/issues/559 for more information. - // lldb allows versions 2 through 5, possibly by mistake. - let version = rest.read_u16()?; - if version != 2 && version != 3 { - return Err(Error::UnknownVersion(u64::from(version))); - } - - let debug_info_offset = rest.read_offset(format).map(DebugInfoOffset)?; - let address_size = rest.read_u8()?; - let segment_size = rest.read_u8()?; - - // unit_length + version + offset + address_size + segment_size - let header_length = format.initial_length_size() + 2 + format.word_size() + 1 + 1; - - // The first tuple following the header in each set begins at an offset that is - // a multiple of the size of a single tuple (that is, the size of a segment selector - // plus twice the size of an address). - let tuple_length = address_size - .checked_mul(2) - .and_then(|x| x.checked_add(segment_size)) - .ok_or(Error::InvalidAddressRange)?; - if tuple_length == 0 { - return Err(Error::InvalidAddressRange)?; - } - let padding = if header_length % tuple_length == 0 { - 0 - } else { - tuple_length - header_length % tuple_length - }; - rest.skip(R::Offset::from_u8(padding))?; - - let encoding = Encoding { - format, - version, - address_size, - // TODO: segment_size - }; - Ok(ArangeHeader { - offset, - encoding, - length, - debug_info_offset, - segment_size, - entries: rest, - }) - } - - /// Return the offset of this header within the `.debug_aranges` section. - #[inline] - pub fn offset(&self) -> DebugArangesOffset<Offset> { - self.offset - } - - /// Return the length of this set of entries, including the header. - #[inline] - pub fn length(&self) -> Offset { - self.length - } - - /// Return the encoding parameters for this set of entries. - #[inline] - pub fn encoding(&self) -> Encoding { - self.encoding - } - - /// Return the segment size for this set of entries. - #[inline] - pub fn segment_size(&self) -> u8 { - self.segment_size - } - - /// Return the offset into the .debug_info section for this set of arange entries. - #[inline] - pub fn debug_info_offset(&self) -> DebugInfoOffset<Offset> { - self.debug_info_offset - } - - /// Return the arange entries in this set. - #[inline] - pub fn entries(&self) -> ArangeEntryIter<R> { - ArangeEntryIter { - input: self.entries.clone(), - encoding: self.encoding, - segment_size: self.segment_size, - } - } -} - -/// An iterator over the aranges from a `.debug_aranges` section. -/// -/// Can be [used with -/// `FallibleIterator`](./index.html#using-with-fallibleiterator). -#[derive(Debug, Clone)] -pub struct ArangeEntryIter<R: Reader> { - input: R, - encoding: Encoding, - segment_size: u8, -} - -impl<R: Reader> ArangeEntryIter<R> { - /// Advance the iterator and return the next arange. - /// - /// Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)` - /// when iteration is complete and all aranges have already been parsed and - /// yielded. If an error occurs while parsing the next arange, then this error - /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`. - pub fn next(&mut self) -> Result<Option<ArangeEntry>> { - if self.input.is_empty() { - return Ok(None); - } - - match ArangeEntry::parse(&mut self.input, self.encoding, self.segment_size) { - Ok(Some(entry)) => Ok(Some(entry)), - Ok(None) => { - self.input.empty(); - Ok(None) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for ArangeEntryIter<R> { - type Item = ArangeEntry; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - ArangeEntryIter::next(self) - } -} - -/// A single parsed arange. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct ArangeEntry { - segment: Option<u64>, - address: u64, - length: u64, -} - -impl ArangeEntry { - /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange. - fn parse<R: Reader>( - input: &mut R, - encoding: Encoding, - segment_size: u8, - ) -> Result<Option<Self>> { - let address_size = encoding.address_size; - - let tuple_length = R::Offset::from_u8(2 * address_size + segment_size); - if tuple_length > input.len() { - input.empty(); - return Ok(None); - } - - let segment = if segment_size != 0 { - input.read_address(segment_size)? - } else { - 0 - }; - let address = input.read_address(address_size)?; - let length = input.read_address(address_size)?; - - match (segment, address, length) { - // This is meant to be a null terminator, but in practice it can occur - // before the end, possibly due to a linker omitting a function and - // leaving an unrelocated entry. - (0, 0, 0) => Self::parse(input, encoding, segment_size), - _ => Ok(Some(ArangeEntry { - segment: if segment_size != 0 { - Some(segment) - } else { - None - }, - address, - length, - })), - } - } - - /// Return the segment selector of this arange. - #[inline] - pub fn segment(&self) -> Option<u64> { - self.segment - } - - /// Return the beginning address of this arange. - #[inline] - pub fn address(&self) -> u64 { - self.address - } - - /// Return the length of this arange. - #[inline] - pub fn length(&self) -> u64 { - self.length - } - - /// Return the range. - #[inline] - pub fn range(&self) -> Range { - Range { - begin: self.address, - end: self.address.wrapping_add(self.length), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::common::{DebugInfoOffset, Format}; - use crate::endianity::LittleEndian; - use crate::read::EndianSlice; - - #[test] - fn test_iterate_headers() { - #[rustfmt::skip] - let buf = [ - // 32-bit length = 28. - 0x1c, 0x00, 0x00, 0x00, - // Version. - 0x02, 0x00, - // Offset. - 0x01, 0x02, 0x03, 0x04, - // Address size. - 0x04, - // Segment size. - 0x00, - // Dummy padding and arange tuples. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - // 32-bit length = 36. - 0x24, 0x00, 0x00, 0x00, - // Version. - 0x02, 0x00, - // Offset. - 0x11, 0x12, 0x13, 0x14, - // Address size. - 0x04, - // Segment size. - 0x00, - // Dummy padding and arange tuples. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - - let debug_aranges = DebugAranges::new(&buf, LittleEndian); - let mut headers = debug_aranges.headers(); - - let header = headers - .next() - .expect("should parse header ok") - .expect("should have a header"); - assert_eq!(header.offset(), DebugArangesOffset(0)); - assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x0403_0201)); - - let header = headers - .next() - .expect("should parse header ok") - .expect("should have a header"); - assert_eq!(header.offset(), DebugArangesOffset(0x20)); - assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x1413_1211)); - } - - #[test] - fn test_parse_header_ok() { - #[rustfmt::skip] - let buf = [ - // 32-bit length = 32. - 0x20, 0x00, 0x00, 0x00, - // Version. - 0x02, 0x00, - // Offset. - 0x01, 0x02, 0x03, 0x04, - // Address size. - 0x08, - // Segment size. - 0x04, - // Length to here = 12, tuple length = 20. - // Padding to tuple length multiple = 4. - 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy arange tuple data. - 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy next arange. - 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ]; - - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - let header = - ArangeHeader::parse(rest, DebugArangesOffset(0x10)).expect("should parse header ok"); - - assert_eq!( - *rest, - EndianSlice::new(&buf[buf.len() - 16..], LittleEndian) - ); - assert_eq!( - header, - ArangeHeader { - offset: DebugArangesOffset(0x10), - encoding: Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 8, - }, - length: 0x20, - debug_info_offset: DebugInfoOffset(0x0403_0201), - segment_size: 4, - entries: EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian), - } - ); - } - - #[test] - fn test_parse_header_overflow_error() { - #[rustfmt::skip] - let buf = [ - // 32-bit length = 32. - 0x20, 0x00, 0x00, 0x00, - // Version. - 0x02, 0x00, - // Offset. - 0x01, 0x02, 0x03, 0x04, - // Address size. - 0xff, - // Segment size. - 0xff, - // Length to here = 12, tuple length = 20. - // Padding to tuple length multiple = 4. - 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy arange tuple data. - 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy next arange. - 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ]; - - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10)) - .expect_err("should fail to parse header"); - assert_eq!(error, Error::InvalidAddressRange); - } - - #[test] - fn test_parse_header_div_by_zero_error() { - #[rustfmt::skip] - let buf = [ - // 32-bit length = 32. - 0x20, 0x00, 0x00, 0x00, - // Version. - 0x02, 0x00, - // Offset. - 0x01, 0x02, 0x03, 0x04, - // Address size = 0. Could cause a division by zero if we aren't - // careful. - 0x00, - // Segment size. - 0x00, - // Length to here = 12, tuple length = 20. - // Padding to tuple length multiple = 4. - 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy arange tuple data. - 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy next arange. - 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ]; - - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10)) - .expect_err("should fail to parse header"); - assert_eq!(error, Error::InvalidAddressRange); - } - - #[test] - fn test_parse_entry_ok() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 4, - }; - let segment_size = 0; - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = - ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); - assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); - assert_eq!( - entry, - Some(ArangeEntry { - segment: None, - address: 0x0403_0201, - length: 0x0807_0605, - }) - ); - } - - #[test] - fn test_parse_entry_segment() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 4, - }; - let segment_size = 8; - #[rustfmt::skip] - let buf = [ - // Segment. - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - // Address. - 0x01, 0x02, 0x03, 0x04, - // Length. - 0x05, 0x06, 0x07, 0x08, - // Next tuple. - 0x09 - ]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = - ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); - assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); - assert_eq!( - entry, - Some(ArangeEntry { - segment: Some(0x1817_1615_1413_1211), - address: 0x0403_0201, - length: 0x0807_0605, - }) - ); - } - - #[test] - fn test_parse_entry_zero() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 4, - }; - let segment_size = 0; - #[rustfmt::skip] - let buf = [ - // Zero tuple. - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // Address. - 0x01, 0x02, 0x03, 0x04, - // Length. - 0x05, 0x06, 0x07, 0x08, - // Next tuple. - 0x09 - ]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = - ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); - assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); - assert_eq!( - entry, - Some(ArangeEntry { - segment: None, - address: 0x0403_0201, - length: 0x0807_0605, - }) - ); - } -} diff --git a/vendor/gimli/src/read/cfi.rs b/vendor/gimli/src/read/cfi.rs deleted file mode 100644 index d92c8b2..0000000 --- a/vendor/gimli/src/read/cfi.rs +++ /dev/null @@ -1,7823 +0,0 @@ -#[cfg(feature = "read")] -use alloc::boxed::Box; - -use core::cmp::{Ord, Ordering}; -use core::fmt::{self, Debug}; -use core::iter::FromIterator; -use core::mem; -use core::num::Wrapping; - -use super::util::{ArrayLike, ArrayVec}; -use crate::common::{ - DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId, Vendor, -}; -use crate::constants::{self, DwEhPe}; -use crate::endianity::Endianity; -use crate::read::{ - EndianSlice, Error, Expression, Reader, ReaderOffset, Result, Section, StoreOnHeap, -}; - -/// `DebugFrame` contains the `.debug_frame` section's frame unwinding -/// information required to unwind to and recover registers from older frames on -/// the stack. For example, this is useful for a debugger that wants to print -/// locals in a backtrace. -/// -/// Most interesting methods are defined in the -/// [`UnwindSection`](trait.UnwindSection.html) trait. -/// -/// ### Differences between `.debug_frame` and `.eh_frame` -/// -/// While the `.debug_frame` section's information has a lot of overlap with the -/// `.eh_frame` section's information, the `.eh_frame` information tends to only -/// encode the subset of information needed for exception handling. Often, only -/// one of `.eh_frame` or `.debug_frame` will be present in an object file. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct DebugFrame<R: Reader> { - section: R, - address_size: u8, - segment_size: u8, - vendor: Vendor, -} - -impl<R: Reader> DebugFrame<R> { - /// Set the size of a target address in bytes. - /// - /// This defaults to the native word size. - /// This is only used if the CIE version is less than 4. - pub fn set_address_size(&mut self, address_size: u8) { - self.address_size = address_size - } - - /// Set the size of a segment selector in bytes. - /// - /// This defaults to 0. - /// This is only used if the CIE version is less than 4. - pub fn set_segment_size(&mut self, segment_size: u8) { - self.segment_size = segment_size - } - - /// Set the vendor extensions to use. - /// - /// This defaults to `Vendor::Default`. - pub fn set_vendor(&mut self, vendor: Vendor) { - self.vendor = vendor; - } -} - -impl<'input, Endian> DebugFrame<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugFrame` instance from the data in the - /// `.debug_frame` section. - /// - /// It is the caller's responsibility to read the section and present it as - /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O - /// loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugFrame, NativeEndian}; - /// - /// // Use with `.debug_frame` - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_frame_section_somehow = || &buf; - /// let debug_frame = DebugFrame::new(read_debug_frame_section_somehow(), NativeEndian); - /// ``` - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R: Reader> Section<R> for DebugFrame<R> { - fn id() -> SectionId { - SectionId::DebugFrame - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R: Reader> From<R> for DebugFrame<R> { - fn from(section: R) -> Self { - // Default to no segments and native word size. - DebugFrame { - section, - address_size: mem::size_of::<usize>() as u8, - segment_size: 0, - vendor: Vendor::Default, - } - } -} - -/// `EhFrameHdr` contains the information about the `.eh_frame_hdr` section. -/// -/// A pointer to the start of the `.eh_frame` data, and optionally, a binary -/// search table of pointers to the `.eh_frame` records that are found in this section. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct EhFrameHdr<R: Reader>(R); - -/// `ParsedEhFrameHdr` contains the parsed information from the `.eh_frame_hdr` section. -#[derive(Clone, Debug)] -pub struct ParsedEhFrameHdr<R: Reader> { - address_size: u8, - section: R, - - eh_frame_ptr: Pointer, - fde_count: u64, - table_enc: DwEhPe, - table: R, -} - -impl<'input, Endian> EhFrameHdr<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Constructs a new `EhFrameHdr` instance from the data in the `.eh_frame_hdr` section. - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R: Reader> EhFrameHdr<R> { - /// Parses this `EhFrameHdr` to a `ParsedEhFrameHdr`. - pub fn parse(&self, bases: &BaseAddresses, address_size: u8) -> Result<ParsedEhFrameHdr<R>> { - let mut reader = self.0.clone(); - let version = reader.read_u8()?; - if version != 1 { - return Err(Error::UnknownVersion(u64::from(version))); - } - - let eh_frame_ptr_enc = parse_pointer_encoding(&mut reader)?; - let fde_count_enc = parse_pointer_encoding(&mut reader)?; - let table_enc = parse_pointer_encoding(&mut reader)?; - - let parameters = PointerEncodingParameters { - bases: &bases.eh_frame_hdr, - func_base: None, - address_size, - section: &self.0, - }; - - // Omitting this pointer is not valid (defeats the purpose of .eh_frame_hdr entirely) - if eh_frame_ptr_enc == constants::DW_EH_PE_omit { - return Err(Error::CannotParseOmitPointerEncoding); - } - let eh_frame_ptr = parse_encoded_pointer(eh_frame_ptr_enc, ¶meters, &mut reader)?; - - let fde_count; - if fde_count_enc == constants::DW_EH_PE_omit || table_enc == constants::DW_EH_PE_omit { - fde_count = 0 - } else { - fde_count = parse_encoded_pointer(fde_count_enc, ¶meters, &mut reader)?.direct()?; - } - - Ok(ParsedEhFrameHdr { - address_size, - section: self.0.clone(), - - eh_frame_ptr, - fde_count, - table_enc, - table: reader, - }) - } -} - -impl<R: Reader> Section<R> for EhFrameHdr<R> { - fn id() -> SectionId { - SectionId::EhFrameHdr - } - - fn reader(&self) -> &R { - &self.0 - } -} - -impl<R: Reader> From<R> for EhFrameHdr<R> { - fn from(section: R) -> Self { - EhFrameHdr(section) - } -} - -impl<R: Reader> ParsedEhFrameHdr<R> { - /// Returns the address of the binary's `.eh_frame` section. - pub fn eh_frame_ptr(&self) -> Pointer { - self.eh_frame_ptr - } - - /// Retrieves the CFI binary search table, if there is one. - pub fn table(&self) -> Option<EhHdrTable<R>> { - // There are two big edge cases here: - // * You search the table for an invalid address. As this is just a binary - // search table, we always have to return a valid result for that (unless - // you specify an address that is lower than the first address in the - // table). Since this means that you have to recheck that the FDE contains - // your address anyways, we just return the first FDE even when the address - // is too low. After all, we're just doing a normal binary search. - // * This falls apart when the table is empty - there is no entry we could - // return. We conclude that an empty table is not really a table at all. - if self.fde_count == 0 { - None - } else { - Some(EhHdrTable { hdr: self }) - } - } -} - -/// An iterator for `.eh_frame_hdr` section's binary search table. -/// -/// Each table entry consists of a tuple containing an `initial_location` and `address`. -/// The `initial location` represents the first address that the targeted FDE -/// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section. -/// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE. -#[derive(Debug)] -pub struct EhHdrTableIter<'a, 'bases, R: Reader> { - hdr: &'a ParsedEhFrameHdr<R>, - table: R, - bases: &'bases BaseAddresses, - remain: u64, -} - -impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> { - /// Yield the next entry in the `EhHdrTableIter`. - pub fn next(&mut self) -> Result<Option<(Pointer, Pointer)>> { - if self.remain == 0 { - return Ok(None); - } - - let parameters = PointerEncodingParameters { - bases: &self.bases.eh_frame_hdr, - func_base: None, - address_size: self.hdr.address_size, - section: &self.hdr.section, - }; - - self.remain -= 1; - let from = parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut self.table)?; - let to = parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut self.table)?; - Ok(Some((from, to))) - } - /// Yield the nth entry in the `EhHdrTableIter` - pub fn nth(&mut self, n: usize) -> Result<Option<(Pointer, Pointer)>> { - use core::convert::TryFrom; - let size = match self.hdr.table_enc.format() { - constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => { - return Err(Error::VariableLengthSearchTable); - } - constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2, - constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4, - constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8, - _ => return Err(Error::UnknownPointerEncoding), - }; - - let row_size = size * 2; - let n = u64::try_from(n).map_err(|_| Error::UnsupportedOffset)?; - self.remain = self.remain.saturating_sub(n); - self.table.skip(R::Offset::from_u64(n * row_size)?)?; - self.next() - } -} - -#[cfg(feature = "fallible-iterator")] -impl<'a, 'bases, R: Reader> fallible_iterator::FallibleIterator for EhHdrTableIter<'a, 'bases, R> { - type Item = (Pointer, Pointer); - type Error = Error; - fn next(&mut self) -> Result<Option<Self::Item>> { - EhHdrTableIter::next(self) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - use core::convert::TryInto; - ( - self.remain.try_into().unwrap_or(0), - self.remain.try_into().ok(), - ) - } - - fn nth(&mut self, n: usize) -> Result<Option<Self::Item>> { - EhHdrTableIter::nth(self, n) - } -} - -/// The CFI binary search table that is an optional part of the `.eh_frame_hdr` section. -#[derive(Debug, Clone)] -pub struct EhHdrTable<'a, R: Reader> { - hdr: &'a ParsedEhFrameHdr<R>, -} - -impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { - /// Return an iterator that can walk the `.eh_frame_hdr` table. - /// - /// Each table entry consists of a tuple containing an `initial_location` and `address`. - /// The `initial location` represents the first address that the targeted FDE - /// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section. - /// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE. - pub fn iter<'bases>(&self, bases: &'bases BaseAddresses) -> EhHdrTableIter<'_, 'bases, R> { - EhHdrTableIter { - hdr: self.hdr, - bases, - remain: self.hdr.fde_count, - table: self.hdr.table.clone(), - } - } - /// *Probably* returns a pointer to the FDE for the given address. - /// - /// This performs a binary search, so if there is no FDE for the given address, - /// this function **will** return a pointer to any other FDE that's close by. - /// - /// To be sure, you **must** call `contains` on the FDE. - pub fn lookup(&self, address: u64, bases: &BaseAddresses) -> Result<Pointer> { - let size = match self.hdr.table_enc.format() { - constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => { - return Err(Error::VariableLengthSearchTable); - } - constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2, - constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4, - constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8, - _ => return Err(Error::UnknownPointerEncoding), - }; - - let row_size = size * 2; - - let mut len = self.hdr.fde_count; - - let mut reader = self.hdr.table.clone(); - - let parameters = PointerEncodingParameters { - bases: &bases.eh_frame_hdr, - func_base: None, - address_size: self.hdr.address_size, - section: &self.hdr.section, - }; - - while len > 1 { - let head = reader.split(R::Offset::from_u64((len / 2) * row_size)?)?; - let tail = reader.clone(); - - let pivot = - parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut reader)?.direct()?; - - match pivot.cmp(&address) { - Ordering::Equal => { - reader = tail; - break; - } - Ordering::Less => { - reader = tail; - len = len - (len / 2); - } - Ordering::Greater => { - reader = head; - len /= 2; - } - } - } - - reader.skip(R::Offset::from_u64(size)?)?; - - parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut reader) - } - - /// Convert a `Pointer` to a section offset. - /// - /// This does not support indirect pointers. - pub fn pointer_to_offset(&self, ptr: Pointer) -> Result<EhFrameOffset<R::Offset>> { - let ptr = ptr.direct()?; - let eh_frame_ptr = self.hdr.eh_frame_ptr().direct()?; - - // Calculate the offset in the EhFrame section - R::Offset::from_u64(ptr - eh_frame_ptr).map(EhFrameOffset) - } - - /// Returns a parsed FDE for the given address, or `NoUnwindInfoForAddress` - /// if there are none. - /// - /// You must provide a function to get its associated CIE. See - /// `PartialFrameDescriptionEntry::parse` for more information. - /// - /// # Example - /// - /// ``` - /// # use gimli::{BaseAddresses, EhFrame, ParsedEhFrameHdr, EndianSlice, NativeEndian, Error, UnwindSection}; - /// # fn foo() -> Result<(), Error> { - /// # let eh_frame: EhFrame<EndianSlice<NativeEndian>> = unreachable!(); - /// # let eh_frame_hdr: ParsedEhFrameHdr<EndianSlice<NativeEndian>> = unimplemented!(); - /// # let addr = 0; - /// # let bases = unimplemented!(); - /// let table = eh_frame_hdr.table().unwrap(); - /// let fde = table.fde_for_address(&eh_frame, &bases, addr, EhFrame::cie_from_offset)?; - /// # Ok(()) - /// # } - /// ``` - pub fn fde_for_address<F>( - &self, - frame: &EhFrame<R>, - bases: &BaseAddresses, - address: u64, - get_cie: F, - ) -> Result<FrameDescriptionEntry<R>> - where - F: FnMut( - &EhFrame<R>, - &BaseAddresses, - EhFrameOffset<R::Offset>, - ) -> Result<CommonInformationEntry<R>>, - { - let fdeptr = self.lookup(address, bases)?; - let offset = self.pointer_to_offset(fdeptr)?; - let entry = frame.fde_from_offset(bases, offset, get_cie)?; - if entry.contains(address) { - Ok(entry) - } else { - Err(Error::NoUnwindInfoForAddress) - } - } - - #[inline] - #[doc(hidden)] - #[deprecated(note = "Method renamed to fde_for_address; use that instead.")] - pub fn lookup_and_parse<F>( - &self, - address: u64, - bases: &BaseAddresses, - frame: EhFrame<R>, - get_cie: F, - ) -> Result<FrameDescriptionEntry<R>> - where - F: FnMut( - &EhFrame<R>, - &BaseAddresses, - EhFrameOffset<R::Offset>, - ) -> Result<CommonInformationEntry<R>>, - { - self.fde_for_address(&frame, bases, address, get_cie) - } - - /// Returns the frame unwind information for the given address, - /// or `NoUnwindInfoForAddress` if there are none. - /// - /// You must provide a function to get the associated CIE. See - /// `PartialFrameDescriptionEntry::parse` for more information. - pub fn unwind_info_for_address<'ctx, F, A: UnwindContextStorage<R>>( - &self, - frame: &EhFrame<R>, - bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext<R, A>, - address: u64, - get_cie: F, - ) -> Result<&'ctx UnwindTableRow<R, A>> - where - F: FnMut( - &EhFrame<R>, - &BaseAddresses, - EhFrameOffset<R::Offset>, - ) -> Result<CommonInformationEntry<R>>, - { - let fde = self.fde_for_address(frame, bases, address, get_cie)?; - fde.unwind_info_for_address(frame, bases, ctx, address) - } -} - -/// `EhFrame` contains the frame unwinding information needed during exception -/// handling found in the `.eh_frame` section. -/// -/// Most interesting methods are defined in the -/// [`UnwindSection`](trait.UnwindSection.html) trait. -/// -/// See -/// [`DebugFrame`](./struct.DebugFrame.html#differences-between-debug_frame-and-eh_frame) -/// for some discussion on the differences between `.debug_frame` and -/// `.eh_frame`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct EhFrame<R: Reader> { - section: R, - address_size: u8, - vendor: Vendor, -} - -impl<R: Reader> EhFrame<R> { - /// Set the size of a target address in bytes. - /// - /// This defaults to the native word size. - pub fn set_address_size(&mut self, address_size: u8) { - self.address_size = address_size - } - - /// Set the vendor extensions to use. - /// - /// This defaults to `Vendor::Default`. - pub fn set_vendor(&mut self, vendor: Vendor) { - self.vendor = vendor; - } -} - -impl<'input, Endian> EhFrame<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `EhFrame` instance from the data in the - /// `.eh_frame` section. - /// - /// It is the caller's responsibility to read the section and present it as - /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O - /// loader on macOS, etc. - /// - /// ``` - /// use gimli::{EhFrame, EndianSlice, NativeEndian}; - /// - /// // Use with `.eh_frame` - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_eh_frame_section_somehow = || &buf; - /// let eh_frame = EhFrame::new(read_eh_frame_section_somehow(), NativeEndian); - /// ``` - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R: Reader> Section<R> for EhFrame<R> { - fn id() -> SectionId { - SectionId::EhFrame - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R: Reader> From<R> for EhFrame<R> { - fn from(section: R) -> Self { - // Default to native word size. - EhFrame { - section, - address_size: mem::size_of::<usize>() as u8, - vendor: Vendor::Default, - } - } -} - -// This has to be `pub` to silence a warning (that is deny(..)'d by default) in -// rustc. Eventually, not having this `pub` will become a hard error. -#[doc(hidden)] -#[allow(missing_docs)] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum CieOffsetEncoding { - U32, - U64, -} - -/// An offset into an `UnwindSection`. -// -// Needed to avoid conflicting implementations of `Into<T>`. -pub trait UnwindOffset<T = usize>: Copy + Debug + Eq + From<T> -where - T: ReaderOffset, -{ - /// Convert an `UnwindOffset<T>` into a `T`. - fn into(self) -> T; -} - -impl<T> UnwindOffset<T> for DebugFrameOffset<T> -where - T: ReaderOffset, -{ - #[inline] - fn into(self) -> T { - self.0 - } -} - -impl<T> UnwindOffset<T> for EhFrameOffset<T> -where - T: ReaderOffset, -{ - #[inline] - fn into(self) -> T { - self.0 - } -} - -/// This trait completely encapsulates everything that is different between -/// `.eh_frame` and `.debug_frame`, as well as all the bits that can change -/// between DWARF versions. -#[doc(hidden)] -pub trait _UnwindSectionPrivate<R: Reader> { - /// Get the underlying section data. - fn section(&self) -> &R; - - /// Returns true if the given length value should be considered an - /// end-of-entries sentinel. - fn length_value_is_end_of_entries(length: R::Offset) -> bool; - - /// Return true if the given offset if the CIE sentinel, false otherwise. - fn is_cie(format: Format, id: u64) -> bool; - - /// Return the CIE offset/ID encoding used by this unwind section with the - /// given DWARF format. - fn cie_offset_encoding(format: Format) -> CieOffsetEncoding; - - /// For `.eh_frame`, CIE offsets are relative to the current position. For - /// `.debug_frame`, they are relative to the start of the section. We always - /// internally store them relative to the section, so we handle translating - /// `.eh_frame`'s relative offsets in this method. If the offset calculation - /// underflows, return `None`. - fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option<R::Offset>; - - /// Does this version of this unwind section encode address and segment - /// sizes in its CIEs? - fn has_address_and_segment_sizes(version: u8) -> bool; - - /// The address size to use if `has_address_and_segment_sizes` returns false. - fn address_size(&self) -> u8; - - /// The segment size to use if `has_address_and_segment_sizes` returns false. - fn segment_size(&self) -> u8; - - /// The vendor extensions to use. - fn vendor(&self) -> Vendor; -} - -/// A section holding unwind information: either `.debug_frame` or -/// `.eh_frame`. See [`DebugFrame`](./struct.DebugFrame.html) and -/// [`EhFrame`](./struct.EhFrame.html) respectively. -pub trait UnwindSection<R: Reader>: Clone + Debug + _UnwindSectionPrivate<R> { - /// The offset type associated with this CFI section. Either - /// `DebugFrameOffset` or `EhFrameOffset`. - type Offset: UnwindOffset<R::Offset>; - - /// Iterate over the `CommonInformationEntry`s and `FrameDescriptionEntry`s - /// in this `.debug_frame` section. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - fn entries<'bases>(&self, bases: &'bases BaseAddresses) -> CfiEntriesIter<'bases, Self, R> { - CfiEntriesIter { - section: self.clone(), - bases, - input: self.section().clone(), - } - } - - /// Parse the `CommonInformationEntry` at the given offset. - fn cie_from_offset( - &self, - bases: &BaseAddresses, - offset: Self::Offset, - ) -> Result<CommonInformationEntry<R>> { - let offset = UnwindOffset::into(offset); - let input = &mut self.section().clone(); - input.skip(offset)?; - CommonInformationEntry::parse(bases, self, input) - } - - /// Parse the `PartialFrameDescriptionEntry` at the given offset. - fn partial_fde_from_offset<'bases>( - &self, - bases: &'bases BaseAddresses, - offset: Self::Offset, - ) -> Result<PartialFrameDescriptionEntry<'bases, Self, R>> { - let offset = UnwindOffset::into(offset); - let input = &mut self.section().clone(); - input.skip(offset)?; - PartialFrameDescriptionEntry::parse_partial(self, bases, input) - } - - /// Parse the `FrameDescriptionEntry` at the given offset. - fn fde_from_offset<F>( - &self, - bases: &BaseAddresses, - offset: Self::Offset, - get_cie: F, - ) -> Result<FrameDescriptionEntry<R>> - where - F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>, - { - let partial = self.partial_fde_from_offset(bases, offset)?; - partial.parse(get_cie) - } - - /// Find the `FrameDescriptionEntry` for the given address. - /// - /// If found, the FDE is returned. If not found, - /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. - /// If parsing fails, the error is returned. - /// - /// You must provide a function to get its associated CIE. See - /// `PartialFrameDescriptionEntry::parse` for more information. - /// - /// Note: this iterates over all FDEs. If available, it is possible - /// to do a binary search with `EhFrameHdr::fde_for_address` instead. - fn fde_for_address<F>( - &self, - bases: &BaseAddresses, - address: u64, - mut get_cie: F, - ) -> Result<FrameDescriptionEntry<R>> - where - F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>, - { - let mut entries = self.entries(bases); - while let Some(entry) = entries.next()? { - match entry { - CieOrFde::Cie(_) => {} - CieOrFde::Fde(partial) => { - let fde = partial.parse(&mut get_cie)?; - if fde.contains(address) { - return Ok(fde); - } - } - } - } - Err(Error::NoUnwindInfoForAddress) - } - - /// Find the frame unwind information for the given address. - /// - /// If found, the unwind information is returned. If not found, - /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or - /// CFI evaluation fails, the error is returned. - /// - /// ``` - /// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindContext, - /// UnwindSection}; - /// - /// # fn foo() -> gimli::Result<()> { - /// # let read_eh_frame_section = || unimplemented!(); - /// // Get the `.eh_frame` section from the object file. Alternatively, - /// // use `EhFrame` with the `.eh_frame` section of the object file. - /// let eh_frame = EhFrame::new(read_eh_frame_section(), NativeEndian); - /// - /// # let get_frame_pc = || unimplemented!(); - /// // Get the address of the PC for a frame you'd like to unwind. - /// let address = get_frame_pc(); - /// - /// // This context is reusable, which cuts down on heap allocations. - /// let ctx = UnwindContext::new(); - /// - /// // Optionally provide base addresses for any relative pointers. If a - /// // base address isn't provided and a pointer is found that is relative to - /// // it, we will return an `Err`. - /// # let address_of_text_section_in_memory = unimplemented!(); - /// # let address_of_got_section_in_memory = unimplemented!(); - /// let bases = BaseAddresses::default() - /// .set_text(address_of_text_section_in_memory) - /// .set_got(address_of_got_section_in_memory); - /// - /// let unwind_info = eh_frame.unwind_info_for_address( - /// &bases, - /// &mut ctx, - /// address, - /// EhFrame::cie_from_offset, - /// )?; - /// - /// # let do_stuff_with = |_| unimplemented!(); - /// do_stuff_with(unwind_info); - /// # let _ = ctx; - /// # unreachable!() - /// # } - /// ``` - #[inline] - fn unwind_info_for_address<'ctx, F, A: UnwindContextStorage<R>>( - &self, - bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext<R, A>, - address: u64, - get_cie: F, - ) -> Result<&'ctx UnwindTableRow<R, A>> - where - F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>, - { - let fde = self.fde_for_address(bases, address, get_cie)?; - fde.unwind_info_for_address(self, bases, ctx, address) - } -} - -impl<R: Reader> _UnwindSectionPrivate<R> for DebugFrame<R> { - fn section(&self) -> &R { - &self.section - } - - fn length_value_is_end_of_entries(_: R::Offset) -> bool { - false - } - - fn is_cie(format: Format, id: u64) -> bool { - match format { - Format::Dwarf32 => id == 0xffff_ffff, - Format::Dwarf64 => id == 0xffff_ffff_ffff_ffff, - } - } - - fn cie_offset_encoding(format: Format) -> CieOffsetEncoding { - match format { - Format::Dwarf32 => CieOffsetEncoding::U32, - Format::Dwarf64 => CieOffsetEncoding::U64, - } - } - - fn resolve_cie_offset(&self, _: R::Offset, offset: R::Offset) -> Option<R::Offset> { - Some(offset) - } - - fn has_address_and_segment_sizes(version: u8) -> bool { - version == 4 - } - - fn address_size(&self) -> u8 { - self.address_size - } - - fn segment_size(&self) -> u8 { - self.segment_size - } - - fn vendor(&self) -> Vendor { - self.vendor - } -} - -impl<R: Reader> UnwindSection<R> for DebugFrame<R> { - type Offset = DebugFrameOffset<R::Offset>; -} - -impl<R: Reader> _UnwindSectionPrivate<R> for EhFrame<R> { - fn section(&self) -> &R { - &self.section - } - - fn length_value_is_end_of_entries(length: R::Offset) -> bool { - length.into_u64() == 0 - } - - fn is_cie(_: Format, id: u64) -> bool { - id == 0 - } - - fn cie_offset_encoding(_format: Format) -> CieOffsetEncoding { - // `.eh_frame` offsets are always 4 bytes, regardless of the DWARF - // format. - CieOffsetEncoding::U32 - } - - fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option<R::Offset> { - base.checked_sub(offset) - } - - fn has_address_and_segment_sizes(_version: u8) -> bool { - false - } - - fn address_size(&self) -> u8 { - self.address_size - } - - fn segment_size(&self) -> u8 { - 0 - } - - fn vendor(&self) -> Vendor { - self.vendor - } -} - -impl<R: Reader> UnwindSection<R> for EhFrame<R> { - type Offset = EhFrameOffset<R::Offset>; -} - -/// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers. -/// -/// During CIE/FDE parsing, if a relative pointer is encountered for a base -/// address that is unknown, an Err will be returned. -/// -/// ``` -/// use gimli::BaseAddresses; -/// -/// # fn foo() { -/// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!(); -/// # let address_of_eh_frame_section_in_memory = unimplemented!(); -/// # let address_of_text_section_in_memory = unimplemented!(); -/// # let address_of_got_section_in_memory = unimplemented!(); -/// # let address_of_the_start_of_current_func = unimplemented!(); -/// let bases = BaseAddresses::default() -/// .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory) -/// .set_eh_frame(address_of_eh_frame_section_in_memory) -/// .set_text(address_of_text_section_in_memory) -/// .set_got(address_of_got_section_in_memory); -/// # let _ = bases; -/// # } -/// ``` -#[derive(Clone, Default, Debug, PartialEq, Eq)] -pub struct BaseAddresses { - /// The base addresses to use for pointers in the `.eh_frame_hdr` section. - pub eh_frame_hdr: SectionBaseAddresses, - - /// The base addresses to use for pointers in the `.eh_frame` section. - pub eh_frame: SectionBaseAddresses, -} - -/// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers -/// in a particular section. -/// -/// See `BaseAddresses` for methods that are helpful in setting these addresses. -#[derive(Clone, Default, Debug, PartialEq, Eq)] -pub struct SectionBaseAddresses { - /// The address of the section containing the pointer. - pub section: Option<u64>, - - /// The base address for text relative pointers. - /// This is generally the address of the `.text` section. - pub text: Option<u64>, - - /// The base address for data relative pointers. - /// - /// For pointers in the `.eh_frame_hdr` section, this is the address - /// of the `.eh_frame_hdr` section - /// - /// For pointers in the `.eh_frame` section, this is generally the - /// global pointer, such as the address of the `.got` section. - pub data: Option<u64>, -} - -impl BaseAddresses { - /// Set the `.eh_frame_hdr` section base address. - #[inline] - pub fn set_eh_frame_hdr(mut self, addr: u64) -> Self { - self.eh_frame_hdr.section = Some(addr); - self.eh_frame_hdr.data = Some(addr); - self - } - - /// Set the `.eh_frame` section base address. - #[inline] - pub fn set_eh_frame(mut self, addr: u64) -> Self { - self.eh_frame.section = Some(addr); - self - } - - /// Set the `.text` section base address. - #[inline] - pub fn set_text(mut self, addr: u64) -> Self { - self.eh_frame_hdr.text = Some(addr); - self.eh_frame.text = Some(addr); - self - } - - /// Set the `.got` section base address. - #[inline] - pub fn set_got(mut self, addr: u64) -> Self { - self.eh_frame.data = Some(addr); - self - } -} - -/// An iterator over CIE and FDE entries in a `.debug_frame` or `.eh_frame` -/// section. -/// -/// Some pointers may be encoded relative to various base addresses. Use the -/// [`BaseAddresses`](./struct.BaseAddresses.html) parameter to provide them. By -/// default, none are provided. If a relative pointer is encountered for a base -/// address that is unknown, an `Err` will be returned and iteration will abort. -/// -/// Can be [used with -/// `FallibleIterator`](./index.html#using-with-fallibleiterator). -/// -/// ``` -/// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindSection}; -/// -/// # fn foo() -> gimli::Result<()> { -/// # let read_eh_frame_somehow = || unimplemented!(); -/// let eh_frame = EhFrame::new(read_eh_frame_somehow(), NativeEndian); -/// -/// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!(); -/// # let address_of_eh_frame_section_in_memory = unimplemented!(); -/// # let address_of_text_section_in_memory = unimplemented!(); -/// # let address_of_got_section_in_memory = unimplemented!(); -/// # let address_of_the_start_of_current_func = unimplemented!(); -/// // Provide base addresses for relative pointers. -/// let bases = BaseAddresses::default() -/// .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory) -/// .set_eh_frame(address_of_eh_frame_section_in_memory) -/// .set_text(address_of_text_section_in_memory) -/// .set_got(address_of_got_section_in_memory); -/// -/// let mut entries = eh_frame.entries(&bases); -/// -/// # let do_stuff_with = |_| unimplemented!(); -/// while let Some(entry) = entries.next()? { -/// do_stuff_with(entry) -/// } -/// # unreachable!() -/// # } -/// ``` -#[derive(Clone, Debug)] -pub struct CfiEntriesIter<'bases, Section, R> -where - R: Reader, - Section: UnwindSection<R>, -{ - section: Section, - bases: &'bases BaseAddresses, - input: R, -} - -impl<'bases, Section, R> CfiEntriesIter<'bases, Section, R> -where - R: Reader, - Section: UnwindSection<R>, -{ - /// Advance the iterator to the next entry. - pub fn next(&mut self) -> Result<Option<CieOrFde<'bases, Section, R>>> { - if self.input.is_empty() { - return Ok(None); - } - - match parse_cfi_entry(self.bases, &self.section, &mut self.input) { - Err(e) => { - self.input.empty(); - Err(e) - } - Ok(None) => { - self.input.empty(); - Ok(None) - } - Ok(Some(entry)) => Ok(Some(entry)), - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<'bases, Section, R> fallible_iterator::FallibleIterator for CfiEntriesIter<'bases, Section, R> -where - R: Reader, - Section: UnwindSection<R>, -{ - type Item = CieOrFde<'bases, Section, R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - CfiEntriesIter::next(self) - } -} - -/// Either a `CommonInformationEntry` (CIE) or a `FrameDescriptionEntry` (FDE). -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CieOrFde<'bases, Section, R> -where - R: Reader, - Section: UnwindSection<R>, -{ - /// This CFI entry is a `CommonInformationEntry`. - Cie(CommonInformationEntry<R>), - /// This CFI entry is a `FrameDescriptionEntry`, however fully parsing it - /// requires parsing its CIE first, so it is left in a partially parsed - /// state. - Fde(PartialFrameDescriptionEntry<'bases, Section, R>), -} - -fn parse_cfi_entry<'bases, Section, R>( - bases: &'bases BaseAddresses, - section: &Section, - input: &mut R, -) -> Result<Option<CieOrFde<'bases, Section, R>>> -where - R: Reader, - Section: UnwindSection<R>, -{ - let (offset, length, format) = loop { - let offset = input.offset_from(section.section()); - let (length, format) = input.read_initial_length()?; - - if Section::length_value_is_end_of_entries(length) { - return Ok(None); - } - - // Hack: skip zero padding inserted by buggy compilers/linkers. - // We require that the padding is a multiple of 32-bits, otherwise - // there is no reliable way to determine when the padding ends. This - // should be okay since CFI entries must be aligned to the address size. - - if length.into_u64() != 0 || format != Format::Dwarf32 { - break (offset, length, format); - } - }; - - let mut rest = input.split(length)?; - let cie_offset_base = rest.offset_from(section.section()); - let cie_id_or_offset = match Section::cie_offset_encoding(format) { - CieOffsetEncoding::U32 => rest.read_u32().map(u64::from)?, - CieOffsetEncoding::U64 => rest.read_u64()?, - }; - - if Section::is_cie(format, cie_id_or_offset) { - let cie = CommonInformationEntry::parse_rest(offset, length, format, bases, section, rest)?; - Ok(Some(CieOrFde::Cie(cie))) - } else { - let cie_offset = R::Offset::from_u64(cie_id_or_offset)?; - let cie_offset = match section.resolve_cie_offset(cie_offset_base, cie_offset) { - None => return Err(Error::OffsetOutOfBounds), - Some(cie_offset) => cie_offset, - }; - - let fde = PartialFrameDescriptionEntry { - offset, - length, - format, - cie_offset: cie_offset.into(), - rest, - section: section.clone(), - bases, - }; - - Ok(Some(CieOrFde::Fde(fde))) - } -} - -/// We support the z-style augmentation [defined by `.eh_frame`][ehframe]. -/// -/// [ehframe]: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub struct Augmentation { - /// > A 'L' may be present at any position after the first character of the - /// > string. This character may only be present if 'z' is the first character - /// > of the string. If present, it indicates the presence of one argument in - /// > the Augmentation Data of the CIE, and a corresponding argument in the - /// > Augmentation Data of the FDE. The argument in the Augmentation Data of - /// > the CIE is 1-byte and represents the pointer encoding used for the - /// > argument in the Augmentation Data of the FDE, which is the address of a - /// > language-specific data area (LSDA). The size of the LSDA pointer is - /// > specified by the pointer encoding used. - lsda: Option<constants::DwEhPe>, - - /// > A 'P' may be present at any position after the first character of the - /// > string. This character may only be present if 'z' is the first character - /// > of the string. If present, it indicates the presence of two arguments in - /// > the Augmentation Data of the CIE. The first argument is 1-byte and - /// > represents the pointer encoding used for the second argument, which is - /// > the address of a personality routine handler. The size of the - /// > personality routine pointer is specified by the pointer encoding used. - personality: Option<(constants::DwEhPe, Pointer)>, - - /// > A 'R' may be present at any position after the first character of the - /// > string. This character may only be present if 'z' is the first character - /// > of the string. If present, The Augmentation Data shall include a 1 byte - /// > argument that represents the pointer encoding for the address pointers - /// > used in the FDE. - fde_address_encoding: Option<constants::DwEhPe>, - - /// True if this CIE's FDEs are trampolines for signal handlers. - is_signal_trampoline: bool, -} - -impl Augmentation { - fn parse<Section, R>( - augmentation_str: &mut R, - bases: &BaseAddresses, - address_size: u8, - section: &Section, - input: &mut R, - ) -> Result<Augmentation> - where - R: Reader, - Section: UnwindSection<R>, - { - debug_assert!( - !augmentation_str.is_empty(), - "Augmentation::parse should only be called if we have an augmentation" - ); - - let mut augmentation = Augmentation::default(); - - let mut parsed_first = false; - let mut data = None; - - while !augmentation_str.is_empty() { - let ch = augmentation_str.read_u8()?; - match ch { - b'z' => { - if parsed_first { - return Err(Error::UnknownAugmentation); - } - - let augmentation_length = input.read_uleb128().and_then(R::Offset::from_u64)?; - data = Some(input.split(augmentation_length)?); - } - b'L' => { - let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?; - let encoding = parse_pointer_encoding(rest)?; - augmentation.lsda = Some(encoding); - } - b'P' => { - let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?; - let encoding = parse_pointer_encoding(rest)?; - let parameters = PointerEncodingParameters { - bases: &bases.eh_frame, - func_base: None, - address_size, - section: section.section(), - }; - - let personality = parse_encoded_pointer(encoding, ¶meters, rest)?; - augmentation.personality = Some((encoding, personality)); - } - b'R' => { - let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?; - let encoding = parse_pointer_encoding(rest)?; - augmentation.fde_address_encoding = Some(encoding); - } - b'S' => augmentation.is_signal_trampoline = true, - _ => return Err(Error::UnknownAugmentation), - } - - parsed_first = true; - } - - Ok(augmentation) - } -} - -/// Parsed augmentation data for a `FrameDescriptEntry`. -#[derive(Clone, Debug, Default, PartialEq, Eq)] -struct AugmentationData { - lsda: Option<Pointer>, -} - -impl AugmentationData { - fn parse<R: Reader>( - augmentation: &Augmentation, - encoding_parameters: &PointerEncodingParameters<R>, - input: &mut R, - ) -> Result<AugmentationData> { - // In theory, we should be iterating over the original augmentation - // string, interpreting each character, and reading the appropriate bits - // out of the augmentation data as we go. However, the only character - // that defines augmentation data in the FDE is the 'L' character, so we - // can just check for its presence directly. - - let aug_data_len = input.read_uleb128().and_then(R::Offset::from_u64)?; - let rest = &mut input.split(aug_data_len)?; - let mut augmentation_data = AugmentationData::default(); - if let Some(encoding) = augmentation.lsda { - let lsda = parse_encoded_pointer(encoding, encoding_parameters, rest)?; - augmentation_data.lsda = Some(lsda); - } - Ok(augmentation_data) - } -} - -/// > A Common Information Entry holds information that is shared among many -/// > Frame Description Entries. There is at least one CIE in every non-empty -/// > `.debug_frame` section. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CommonInformationEntry<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// The offset of this entry from the start of its containing section. - offset: Offset, - - /// > A constant that gives the number of bytes of the CIE structure, not - /// > including the length field itself (see Section 7.2.2). The size of the - /// > length field plus the value of length must be an integral multiple of - /// > the address size. - length: Offset, - - format: Format, - - /// > A version number (see Section 7.23). This number is specific to the - /// > call frame information and is independent of the DWARF version number. - version: u8, - - /// The parsed augmentation, if any. - augmentation: Option<Augmentation>, - - /// > The size of a target address in this CIE and any FDEs that use it, in - /// > bytes. If a compilation unit exists for this frame, its address size - /// > must match the address size here. - address_size: u8, - - /// "The size of a segment selector in this CIE and any FDEs that use it, in - /// bytes." - segment_size: u8, - - /// "A constant that is factored out of all advance location instructions - /// (see Section 6.4.2.1)." - code_alignment_factor: u64, - - /// > A constant that is factored out of certain offset instructions (see - /// > below). The resulting value is (operand * data_alignment_factor). - data_alignment_factor: i64, - - /// > An unsigned LEB128 constant that indicates which column in the rule - /// > table represents the return address of the function. Note that this - /// > column might not correspond to an actual machine register. - return_address_register: Register, - - /// > A sequence of rules that are interpreted to create the initial setting - /// > of each column in the table. - /// - /// > The default rule for all columns before interpretation of the initial - /// > instructions is the undefined rule. However, an ABI authoring body or a - /// > compilation system authoring body may specify an alternate default - /// > value for any or all columns. - /// - /// This is followed by `DW_CFA_nop` padding until the end of `length` bytes - /// in the input. - initial_instructions: R, -} - -impl<R: Reader> CommonInformationEntry<R> { - fn parse<Section: UnwindSection<R>>( - bases: &BaseAddresses, - section: &Section, - input: &mut R, - ) -> Result<CommonInformationEntry<R>> { - match parse_cfi_entry(bases, section, input)? { - Some(CieOrFde::Cie(cie)) => Ok(cie), - Some(CieOrFde::Fde(_)) => Err(Error::NotCieId), - None => Err(Error::NoEntryAtGivenOffset), - } - } - - fn parse_rest<Section: UnwindSection<R>>( - offset: R::Offset, - length: R::Offset, - format: Format, - bases: &BaseAddresses, - section: &Section, - mut rest: R, - ) -> Result<CommonInformationEntry<R>> { - let version = rest.read_u8()?; - - // Version 1 of `.debug_frame` corresponds to DWARF 2, and then for - // DWARF 3 and 4, I think they decided to just match the standard's - // version. - match version { - 1 | 3 | 4 => (), - _ => return Err(Error::UnknownVersion(u64::from(version))), - } - - let mut augmentation_string = rest.read_null_terminated_slice()?; - - let (address_size, segment_size) = if Section::has_address_and_segment_sizes(version) { - let address_size = rest.read_u8()?; - let segment_size = rest.read_u8()?; - (address_size, segment_size) - } else { - (section.address_size(), section.segment_size()) - }; - - let code_alignment_factor = rest.read_uleb128()?; - let data_alignment_factor = rest.read_sleb128()?; - - let return_address_register = if version == 1 { - Register(rest.read_u8()?.into()) - } else { - rest.read_uleb128().and_then(Register::from_u64)? - }; - - let augmentation = if augmentation_string.is_empty() { - None - } else { - Some(Augmentation::parse( - &mut augmentation_string, - bases, - address_size, - section, - &mut rest, - )?) - }; - - let entry = CommonInformationEntry { - offset, - length, - format, - version, - augmentation, - address_size, - segment_size, - code_alignment_factor, - data_alignment_factor, - return_address_register, - initial_instructions: rest, - }; - - Ok(entry) - } -} - -/// # Signal Safe Methods -/// -/// These methods are guaranteed not to allocate, acquire locks, or perform any -/// other signal-unsafe operations. -impl<R: Reader> CommonInformationEntry<R> { - /// Get the offset of this entry from the start of its containing section. - pub fn offset(&self) -> R::Offset { - self.offset - } - - /// Return the encoding parameters for this CIE. - pub fn encoding(&self) -> Encoding { - Encoding { - format: self.format, - version: u16::from(self.version), - address_size: self.address_size, - } - } - - /// The size of addresses (in bytes) in this CIE. - pub fn address_size(&self) -> u8 { - self.address_size - } - - /// Iterate over this CIE's initial instructions. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn instructions<'a, Section>( - &self, - section: &'a Section, - bases: &'a BaseAddresses, - ) -> CallFrameInstructionIter<'a, R> - where - Section: UnwindSection<R>, - { - CallFrameInstructionIter { - input: self.initial_instructions.clone(), - address_encoding: None, - parameters: PointerEncodingParameters { - bases: &bases.eh_frame, - func_base: None, - address_size: self.address_size, - section: section.section(), - }, - vendor: section.vendor(), - } - } - - /// > A constant that gives the number of bytes of the CIE structure, not - /// > including the length field itself (see Section 7.2.2). The size of the - /// > length field plus the value of length must be an integral multiple of - /// > the address size. - pub fn entry_len(&self) -> R::Offset { - self.length - } - - /// > A version number (see Section 7.23). This number is specific to the - /// > call frame information and is independent of the DWARF version number. - pub fn version(&self) -> u8 { - self.version - } - - /// Get the augmentation data, if any exists. - /// - /// The only augmentation understood by `gimli` is that which is defined by - /// `.eh_frame`. - pub fn augmentation(&self) -> Option<&Augmentation> { - self.augmentation.as_ref() - } - - /// True if this CIE's FDEs have a LSDA. - pub fn has_lsda(&self) -> bool { - self.augmentation.map_or(false, |a| a.lsda.is_some()) - } - - /// Return the encoding of the LSDA address for this CIE's FDEs. - pub fn lsda_encoding(&self) -> Option<constants::DwEhPe> { - self.augmentation.and_then(|a| a.lsda) - } - - /// Return the encoding and address of the personality routine handler - /// for this CIE's FDEs. - pub fn personality_with_encoding(&self) -> Option<(constants::DwEhPe, Pointer)> { - self.augmentation.as_ref().and_then(|a| a.personality) - } - - /// Return the address of the personality routine handler - /// for this CIE's FDEs. - pub fn personality(&self) -> Option<Pointer> { - self.augmentation - .as_ref() - .and_then(|a| a.personality) - .map(|(_, p)| p) - } - - /// Return the encoding of the addresses for this CIE's FDEs. - pub fn fde_address_encoding(&self) -> Option<constants::DwEhPe> { - self.augmentation.and_then(|a| a.fde_address_encoding) - } - - /// True if this CIE's FDEs are trampolines for signal handlers. - pub fn is_signal_trampoline(&self) -> bool { - self.augmentation.map_or(false, |a| a.is_signal_trampoline) - } - - /// > A constant that is factored out of all advance location instructions - /// > (see Section 6.4.2.1). - pub fn code_alignment_factor(&self) -> u64 { - self.code_alignment_factor - } - - /// > A constant that is factored out of certain offset instructions (see - /// > below). The resulting value is (operand * data_alignment_factor). - pub fn data_alignment_factor(&self) -> i64 { - self.data_alignment_factor - } - - /// > An unsigned ... constant that indicates which column in the rule - /// > table represents the return address of the function. Note that this - /// > column might not correspond to an actual machine register. - pub fn return_address_register(&self) -> Register { - self.return_address_register - } -} - -/// A partially parsed `FrameDescriptionEntry`. -/// -/// Fully parsing this FDE requires first parsing its CIE. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PartialFrameDescriptionEntry<'bases, Section, R> -where - R: Reader, - Section: UnwindSection<R>, -{ - offset: R::Offset, - length: R::Offset, - format: Format, - cie_offset: Section::Offset, - rest: R, - section: Section, - bases: &'bases BaseAddresses, -} - -impl<'bases, Section, R> PartialFrameDescriptionEntry<'bases, Section, R> -where - R: Reader, - Section: UnwindSection<R>, -{ - fn parse_partial( - section: &Section, - bases: &'bases BaseAddresses, - input: &mut R, - ) -> Result<PartialFrameDescriptionEntry<'bases, Section, R>> { - match parse_cfi_entry(bases, section, input)? { - Some(CieOrFde::Cie(_)) => Err(Error::NotFdePointer), - Some(CieOrFde::Fde(partial)) => Ok(partial), - None => Err(Error::NoEntryAtGivenOffset), - } - } - - /// Fully parse this FDE. - /// - /// You must provide a function get its associated CIE (either by parsing it - /// on demand, or looking it up in some table mapping offsets to CIEs that - /// you've already parsed, etc.) - pub fn parse<F>(&self, get_cie: F) -> Result<FrameDescriptionEntry<R>> - where - F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result<CommonInformationEntry<R>>, - { - FrameDescriptionEntry::parse_rest( - self.offset, - self.length, - self.format, - self.cie_offset, - self.rest.clone(), - &self.section, - self.bases, - get_cie, - ) - } - - /// Get the offset of this entry from the start of its containing section. - pub fn offset(&self) -> R::Offset { - self.offset - } - - /// Get the offset of this FDE's CIE. - pub fn cie_offset(&self) -> Section::Offset { - self.cie_offset - } - - /// > A constant that gives the number of bytes of the header and - /// > instruction stream for this function, not including the length field - /// > itself (see Section 7.2.2). The size of the length field plus the value - /// > of length must be an integral multiple of the address size. - pub fn entry_len(&self) -> R::Offset { - self.length - } -} - -/// A `FrameDescriptionEntry` is a set of CFA instructions for an address range. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct FrameDescriptionEntry<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// The start of this entry within its containing section. - offset: Offset, - - /// > A constant that gives the number of bytes of the header and - /// > instruction stream for this function, not including the length field - /// > itself (see Section 7.2.2). The size of the length field plus the value - /// > of length must be an integral multiple of the address size. - length: Offset, - - format: Format, - - /// "A constant offset into the .debug_frame section that denotes the CIE - /// that is associated with this FDE." - /// - /// This is the CIE at that offset. - cie: CommonInformationEntry<R, Offset>, - - /// > The address of the first location associated with this table entry. If - /// > the segment_size field of this FDE's CIE is non-zero, the initial - /// > location is preceded by a segment selector of the given length. - initial_segment: u64, - initial_address: u64, - - /// "The number of bytes of program instructions described by this entry." - address_range: u64, - - /// The parsed augmentation data, if we have any. - augmentation: Option<AugmentationData>, - - /// "A sequence of table defining instructions that are described below." - /// - /// This is followed by `DW_CFA_nop` padding until `length` bytes of the - /// input are consumed. - instructions: R, -} - -impl<R: Reader> FrameDescriptionEntry<R> { - fn parse_rest<Section, F>( - offset: R::Offset, - length: R::Offset, - format: Format, - cie_pointer: Section::Offset, - mut rest: R, - section: &Section, - bases: &BaseAddresses, - mut get_cie: F, - ) -> Result<FrameDescriptionEntry<R>> - where - Section: UnwindSection<R>, - F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result<CommonInformationEntry<R>>, - { - let cie = get_cie(section, bases, cie_pointer)?; - - let initial_segment = if cie.segment_size > 0 { - rest.read_address(cie.segment_size)? - } else { - 0 - }; - - let mut parameters = PointerEncodingParameters { - bases: &bases.eh_frame, - func_base: None, - address_size: cie.address_size, - section: section.section(), - }; - - let (initial_address, address_range) = Self::parse_addresses(&mut rest, &cie, ¶meters)?; - parameters.func_base = Some(initial_address); - - let aug_data = if let Some(ref augmentation) = cie.augmentation { - Some(AugmentationData::parse( - augmentation, - ¶meters, - &mut rest, - )?) - } else { - None - }; - - let entry = FrameDescriptionEntry { - offset, - length, - format, - cie, - initial_segment, - initial_address, - address_range, - augmentation: aug_data, - instructions: rest, - }; - - Ok(entry) - } - - fn parse_addresses( - input: &mut R, - cie: &CommonInformationEntry<R>, - parameters: &PointerEncodingParameters<R>, - ) -> Result<(u64, u64)> { - let encoding = cie.augmentation().and_then(|a| a.fde_address_encoding); - if let Some(encoding) = encoding { - let initial_address = parse_encoded_pointer(encoding, parameters, input)?; - - // Ignore indirection. - let initial_address = initial_address.pointer(); - - // Address ranges cannot be relative to anything, so just grab the - // data format bits from the encoding. - let address_range = parse_encoded_pointer(encoding.format(), parameters, input)?; - Ok((initial_address, address_range.pointer())) - } else { - let initial_address = input.read_address(cie.address_size)?; - let address_range = input.read_address(cie.address_size)?; - Ok((initial_address, address_range)) - } - } - - /// Return the table of unwind information for this FDE. - #[inline] - pub fn rows<'a, 'ctx, Section: UnwindSection<R>, A: UnwindContextStorage<R>>( - &self, - section: &'a Section, - bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext<R, A>, - ) -> Result<UnwindTable<'a, 'ctx, R, A>> { - UnwindTable::new(section, bases, ctx, self) - } - - /// Find the frame unwind information for the given address. - /// - /// If found, the unwind information is returned along with the reset - /// context in the form `Ok((unwind_info, context))`. If not found, - /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or - /// CFI evaluation fails, the error is returned. - pub fn unwind_info_for_address<'ctx, Section: UnwindSection<R>, A: UnwindContextStorage<R>>( - &self, - section: &Section, - bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext<R, A>, - address: u64, - ) -> Result<&'ctx UnwindTableRow<R, A>> { - let mut table = self.rows(section, bases, ctx)?; - while let Some(row) = table.next_row()? { - if row.contains(address) { - return Ok(table.ctx.row()); - } - } - Err(Error::NoUnwindInfoForAddress) - } -} - -/// # Signal Safe Methods -/// -/// These methods are guaranteed not to allocate, acquire locks, or perform any -/// other signal-unsafe operations. -#[allow(clippy::len_without_is_empty)] -impl<R: Reader> FrameDescriptionEntry<R> { - /// Get the offset of this entry from the start of its containing section. - pub fn offset(&self) -> R::Offset { - self.offset - } - - /// Get a reference to this FDE's CIE. - pub fn cie(&self) -> &CommonInformationEntry<R> { - &self.cie - } - - /// > A constant that gives the number of bytes of the header and - /// > instruction stream for this function, not including the length field - /// > itself (see Section 7.2.2). The size of the length field plus the value - /// > of length must be an integral multiple of the address size. - pub fn entry_len(&self) -> R::Offset { - self.length - } - - /// Iterate over this FDE's instructions. - /// - /// Will not include the CIE's initial instructions, if you want those do - /// `fde.cie().instructions()` first. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn instructions<'a, Section>( - &self, - section: &'a Section, - bases: &'a BaseAddresses, - ) -> CallFrameInstructionIter<'a, R> - where - Section: UnwindSection<R>, - { - CallFrameInstructionIter { - input: self.instructions.clone(), - address_encoding: self.cie.augmentation().and_then(|a| a.fde_address_encoding), - parameters: PointerEncodingParameters { - bases: &bases.eh_frame, - func_base: None, - address_size: self.cie.address_size, - section: section.section(), - }, - vendor: section.vendor(), - } - } - - /// The first address for which this entry has unwind information for. - pub fn initial_address(&self) -> u64 { - self.initial_address - } - - /// The number of bytes of instructions that this entry has unwind - /// information for. - pub fn len(&self) -> u64 { - self.address_range - } - - /// Return `true` if the given address is within this FDE, `false` - /// otherwise. - /// - /// This is equivalent to `entry.initial_address() <= address < - /// entry.initial_address() + entry.len()`. - pub fn contains(&self, address: u64) -> bool { - let start = self.initial_address(); - let end = start + self.len(); - start <= address && address < end - } - - /// The address of this FDE's language-specific data area (LSDA), if it has - /// any. - pub fn lsda(&self) -> Option<Pointer> { - self.augmentation.as_ref().and_then(|a| a.lsda) - } - - /// Return true if this FDE's function is a trampoline for a signal handler. - #[inline] - pub fn is_signal_trampoline(&self) -> bool { - self.cie().is_signal_trampoline() - } - - /// Return the address of the FDE's function's personality routine - /// handler. The personality routine does language-specific clean up when - /// unwinding the stack frames with the intent to not run them again. - #[inline] - pub fn personality(&self) -> Option<Pointer> { - self.cie().personality() - } -} - -/// Specification of what storage should be used for [`UnwindContext`]. -/// -#[cfg_attr( - feature = "read", - doc = " -Normally you would only need to use [`StoreOnHeap`], which places the stack -on the heap using [`Vec`]. This is the default storage type parameter for [`UnwindContext`]. -" -)] -/// -/// If you need to avoid [`UnwindContext`] from allocating memory, e.g. for signal safety, -/// you can provide you own storage specification: -/// ```rust,no_run -/// # use gimli::*; -/// # -/// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry<gimli::EndianSlice<'a, gimli::LittleEndian>>) -/// # -> gimli::Result<()> { -/// # let eh_frame: gimli::EhFrame<_> = unreachable!(); -/// # let bases = unimplemented!(); -/// # -/// struct StoreOnStack; -/// -/// impl<R: Reader> UnwindContextStorage<R> for StoreOnStack { -/// type Rules = [(Register, RegisterRule<R>); 192]; -/// type Stack = [UnwindTableRow<R, Self>; 4]; -/// } -/// -/// let mut ctx = UnwindContext::<_, StoreOnStack>::new_in(); -/// -/// // Initialize the context by evaluating the CIE's initial instruction program, -/// // and generate the unwind table. -/// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?; -/// while let Some(row) = table.next_row()? { -/// // Do stuff with each row... -/// # let _ = row; -/// } -/// # unreachable!() -/// # } -/// ``` -pub trait UnwindContextStorage<R: Reader>: Sized { - /// The storage used for register rules in a unwind table row. - /// - /// Note that this is nested within the stack. - type Rules: ArrayLike<Item = (Register, RegisterRule<R>)>; - - /// The storage used for unwind table row stack. - type Stack: ArrayLike<Item = UnwindTableRow<R, Self>>; -} - -#[cfg(feature = "read")] -const MAX_RULES: usize = 192; -#[cfg(feature = "read")] -const MAX_UNWIND_STACK_DEPTH: usize = 4; - -#[cfg(feature = "read")] -impl<R: Reader> UnwindContextStorage<R> for StoreOnHeap { - type Rules = [(Register, RegisterRule<R>); MAX_RULES]; - type Stack = Box<[UnwindTableRow<R, Self>; MAX_UNWIND_STACK_DEPTH]>; -} - -/// Common context needed when evaluating the call frame unwinding information. -/// -/// This structure can be large so it is advisable to place it on the heap. -/// To avoid re-allocating the context multiple times when evaluating multiple -/// CFI programs, it can be reused. -/// -/// ``` -/// use gimli::{UnwindContext, UnwindTable}; -/// -/// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry<gimli::EndianSlice<'a, gimli::LittleEndian>>) -/// # -> gimli::Result<()> { -/// # let eh_frame: gimli::EhFrame<_> = unreachable!(); -/// # let bases = unimplemented!(); -/// // An uninitialized context. -/// let mut ctx = Box::new(UnwindContext::new()); -/// -/// // Initialize the context by evaluating the CIE's initial instruction program, -/// // and generate the unwind table. -/// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?; -/// while let Some(row) = table.next_row()? { -/// // Do stuff with each row... -/// # let _ = row; -/// } -/// # unreachable!() -/// # } -/// ``` -#[derive(Clone, PartialEq, Eq)] -pub struct UnwindContext<R: Reader, A: UnwindContextStorage<R> = StoreOnHeap> { - // Stack of rows. The last row is the row currently being built by the - // program. There is always at least one row. The vast majority of CFI - // programs will only ever have one row on the stack. - stack: ArrayVec<A::Stack>, - - // If we are evaluating an FDE's instructions, then `is_initialized` will be - // `true`. If `initial_rule` is `Some`, then the initial register rules are either - // all default rules or have just 1 non-default rule, stored in `initial_rule`. - // If it's `None`, `stack[0]` will contain the initial register rules - // described by the CIE's initial instructions. These rules are used by - // `DW_CFA_restore`. Otherwise, when we are currently evaluating a CIE's - // initial instructions, `is_initialized` will be `false` and initial rules - // cannot be read. - initial_rule: Option<(Register, RegisterRule<R>)>, - - is_initialized: bool, -} - -impl<R: Reader, S: UnwindContextStorage<R>> Debug for UnwindContext<R, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("UnwindContext") - .field("stack", &self.stack) - .field("initial_rule", &self.initial_rule) - .field("is_initialized", &self.is_initialized) - .finish() - } -} - -impl<R: Reader, A: UnwindContextStorage<R>> Default for UnwindContext<R, A> { - fn default() -> Self { - Self::new_in() - } -} - -#[cfg(feature = "read")] -impl<R: Reader> UnwindContext<R> { - /// Construct a new call frame unwinding context. - pub fn new() -> Self { - Self::new_in() - } -} - -/// # Signal Safe Methods -/// -/// These methods are guaranteed not to allocate, acquire locks, or perform any -/// other signal-unsafe operations, if an non-allocating storage is used. -impl<R: Reader, A: UnwindContextStorage<R>> UnwindContext<R, A> { - /// Construct a new call frame unwinding context. - pub fn new_in() -> Self { - let mut ctx = UnwindContext { - stack: Default::default(), - initial_rule: None, - is_initialized: false, - }; - ctx.reset(); - ctx - } - - /// Run the CIE's initial instructions and initialize this `UnwindContext`. - fn initialize<Section: UnwindSection<R>>( - &mut self, - section: &Section, - bases: &BaseAddresses, - cie: &CommonInformationEntry<R>, - ) -> Result<()> { - // Always reset because previous initialization failure may leave dirty state. - self.reset(); - - let mut table = UnwindTable::new_for_cie(section, bases, self, cie); - while table.next_row()?.is_some() {} - - self.save_initial_rules()?; - Ok(()) - } - - fn reset(&mut self) { - self.stack.clear(); - self.stack.try_push(UnwindTableRow::default()).unwrap(); - debug_assert!(self.stack[0].is_default()); - self.initial_rule = None; - self.is_initialized = false; - } - - fn row(&self) -> &UnwindTableRow<R, A> { - self.stack.last().unwrap() - } - - fn row_mut(&mut self) -> &mut UnwindTableRow<R, A> { - self.stack.last_mut().unwrap() - } - - fn save_initial_rules(&mut self) -> Result<()> { - debug_assert!(!self.is_initialized); - self.initial_rule = match *self.stack.last().unwrap().registers.rules { - // All rules are default (undefined). In this case just synthesize - // an undefined rule. - [] => Some((Register(0), RegisterRule::Undefined)), - [ref rule] => Some(rule.clone()), - _ => { - let rules = self.stack.last().unwrap().clone(); - self.stack - .try_insert(0, rules) - .map_err(|_| Error::StackFull)?; - None - } - }; - self.is_initialized = true; - Ok(()) - } - - fn start_address(&self) -> u64 { - self.row().start_address - } - - fn set_start_address(&mut self, start_address: u64) { - let row = self.row_mut(); - row.start_address = start_address; - } - - fn set_register_rule(&mut self, register: Register, rule: RegisterRule<R>) -> Result<()> { - let row = self.row_mut(); - row.registers.set(register, rule) - } - - /// Returns `None` if we have not completed evaluation of a CIE's initial - /// instructions. - fn get_initial_rule(&self, register: Register) -> Option<RegisterRule<R>> { - if !self.is_initialized { - return None; - } - Some(match self.initial_rule { - None => self.stack[0].registers.get(register), - Some((r, ref rule)) if r == register => rule.clone(), - _ => RegisterRule::Undefined, - }) - } - - fn set_cfa(&mut self, cfa: CfaRule<R>) { - self.row_mut().cfa = cfa; - } - - fn cfa_mut(&mut self) -> &mut CfaRule<R> { - &mut self.row_mut().cfa - } - - fn push_row(&mut self) -> Result<()> { - let new_row = self.row().clone(); - self.stack.try_push(new_row).map_err(|_| Error::StackFull) - } - - fn pop_row(&mut self) -> Result<()> { - let min_size = if self.is_initialized && self.initial_rule.is_none() { - 2 - } else { - 1 - }; - if self.stack.len() <= min_size { - return Err(Error::PopWithEmptyStack); - } - self.stack.pop().unwrap(); - Ok(()) - } -} - -/// The `UnwindTable` iteratively evaluates a `FrameDescriptionEntry`'s -/// `CallFrameInstruction` program, yielding the each row one at a time. -/// -/// > 6.4.1 Structure of Call Frame Information -/// > -/// > DWARF supports virtual unwinding by defining an architecture independent -/// > basis for recording how procedures save and restore registers during their -/// > lifetimes. This basis must be augmented on some machines with specific -/// > information that is defined by an architecture specific ABI authoring -/// > committee, a hardware vendor, or a compiler producer. The body defining a -/// > specific augmentation is referred to below as the “augmenter.” -/// > -/// > Abstractly, this mechanism describes a very large table that has the -/// > following structure: -/// > -/// > <table> -/// > <tr> -/// > <th>LOC</th><th>CFA</th><th>R0</th><th>R1</th><td>...</td><th>RN</th> -/// > </tr> -/// > <tr> -/// > <th>L0</th> <td></td> <td></td> <td></td> <td></td> <td></td> -/// > </tr> -/// > <tr> -/// > <th>L1</th> <td></td> <td></td> <td></td> <td></td> <td></td> -/// > </tr> -/// > <tr> -/// > <td>...</td><td></td> <td></td> <td></td> <td></td> <td></td> -/// > </tr> -/// > <tr> -/// > <th>LN</th> <td></td> <td></td> <td></td> <td></td> <td></td> -/// > </tr> -/// > </table> -/// > -/// > The first column indicates an address for every location that contains code -/// > in a program. (In shared objects, this is an object-relative offset.) The -/// > remaining columns contain virtual unwinding rules that are associated with -/// > the indicated location. -/// > -/// > The CFA column defines the rule which computes the Canonical Frame Address -/// > value; it may be either a register and a signed offset that are added -/// > together, or a DWARF expression that is evaluated. -/// > -/// > The remaining columns are labeled by register number. This includes some -/// > registers that have special designation on some architectures such as the PC -/// > and the stack pointer register. (The actual mapping of registers for a -/// > particular architecture is defined by the augmenter.) The register columns -/// > contain rules that describe whether a given register has been saved and the -/// > rule to find the value for the register in the previous frame. -/// > -/// > ... -/// > -/// > This table would be extremely large if actually constructed as -/// > described. Most of the entries at any point in the table are identical to -/// > the ones above them. The whole table can be represented quite compactly by -/// > recording just the differences starting at the beginning address of each -/// > subroutine in the program. -#[derive(Debug)] -pub struct UnwindTable<'a, 'ctx, R: Reader, A: UnwindContextStorage<R> = StoreOnHeap> { - code_alignment_factor: Wrapping<u64>, - data_alignment_factor: Wrapping<i64>, - next_start_address: u64, - last_end_address: u64, - returned_last_row: bool, - current_row_valid: bool, - instructions: CallFrameInstructionIter<'a, R>, - ctx: &'ctx mut UnwindContext<R, A>, -} - -/// # Signal Safe Methods -/// -/// These methods are guaranteed not to allocate, acquire locks, or perform any -/// other signal-unsafe operations. -impl<'a, 'ctx, R: Reader, A: UnwindContextStorage<R>> UnwindTable<'a, 'ctx, R, A> { - /// Construct a new `UnwindTable` for the given - /// `FrameDescriptionEntry`'s CFI unwinding program. - pub fn new<Section: UnwindSection<R>>( - section: &'a Section, - bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext<R, A>, - fde: &FrameDescriptionEntry<R>, - ) -> Result<Self> { - ctx.initialize(section, bases, fde.cie())?; - Ok(Self::new_for_fde(section, bases, ctx, fde)) - } - - fn new_for_fde<Section: UnwindSection<R>>( - section: &'a Section, - bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext<R, A>, - fde: &FrameDescriptionEntry<R>, - ) -> Self { - assert!(ctx.stack.len() >= 1); - UnwindTable { - code_alignment_factor: Wrapping(fde.cie().code_alignment_factor()), - data_alignment_factor: Wrapping(fde.cie().data_alignment_factor()), - next_start_address: fde.initial_address(), - last_end_address: fde.initial_address().wrapping_add(fde.len()), - returned_last_row: false, - current_row_valid: false, - instructions: fde.instructions(section, bases), - ctx, - } - } - - fn new_for_cie<Section: UnwindSection<R>>( - section: &'a Section, - bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext<R, A>, - cie: &CommonInformationEntry<R>, - ) -> Self { - assert!(ctx.stack.len() >= 1); - UnwindTable { - code_alignment_factor: Wrapping(cie.code_alignment_factor()), - data_alignment_factor: Wrapping(cie.data_alignment_factor()), - next_start_address: 0, - last_end_address: 0, - returned_last_row: false, - current_row_valid: false, - instructions: cie.instructions(section, bases), - ctx, - } - } - - /// Evaluate call frame instructions until the next row of the table is - /// completed, and return it. - /// - /// Unfortunately, this cannot be used with `FallibleIterator` because of - /// the restricted lifetime of the yielded item. - pub fn next_row(&mut self) -> Result<Option<&UnwindTableRow<R, A>>> { - assert!(self.ctx.stack.len() >= 1); - self.ctx.set_start_address(self.next_start_address); - self.current_row_valid = false; - - loop { - match self.instructions.next() { - Err(e) => return Err(e), - - Ok(None) => { - if self.returned_last_row { - return Ok(None); - } - - let row = self.ctx.row_mut(); - row.end_address = self.last_end_address; - - self.returned_last_row = true; - self.current_row_valid = true; - return Ok(Some(row)); - } - - Ok(Some(instruction)) => { - if self.evaluate(instruction)? { - self.current_row_valid = true; - return Ok(Some(self.ctx.row())); - } - } - }; - } - } - - /// Returns the current row with the lifetime of the context. - pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow<R, A>> { - if self.current_row_valid { - Some(self.ctx.row()) - } else { - None - } - } - - /// Evaluate one call frame instruction. Return `Ok(true)` if the row is - /// complete, `Ok(false)` otherwise. - fn evaluate(&mut self, instruction: CallFrameInstruction<R>) -> Result<bool> { - use crate::CallFrameInstruction::*; - - match instruction { - // Instructions that complete the current row and advance the - // address for the next row. - SetLoc { address } => { - if address < self.ctx.start_address() { - return Err(Error::InvalidAddressRange); - } - - self.next_start_address = address; - self.ctx.row_mut().end_address = self.next_start_address; - return Ok(true); - } - AdvanceLoc { delta } => { - let delta = Wrapping(u64::from(delta)) * self.code_alignment_factor; - self.next_start_address = (Wrapping(self.ctx.start_address()) + delta).0; - self.ctx.row_mut().end_address = self.next_start_address; - return Ok(true); - } - - // Instructions that modify the CFA. - DefCfa { register, offset } => { - self.ctx.set_cfa(CfaRule::RegisterAndOffset { - register, - offset: offset as i64, - }); - } - DefCfaSf { - register, - factored_offset, - } => { - let data_align = self.data_alignment_factor; - self.ctx.set_cfa(CfaRule::RegisterAndOffset { - register, - offset: (Wrapping(factored_offset) * data_align).0, - }); - } - DefCfaRegister { register } => { - if let CfaRule::RegisterAndOffset { - register: ref mut reg, - .. - } = *self.ctx.cfa_mut() - { - *reg = register; - } else { - return Err(Error::CfiInstructionInInvalidContext); - } - } - DefCfaOffset { offset } => { - if let CfaRule::RegisterAndOffset { - offset: ref mut off, - .. - } = *self.ctx.cfa_mut() - { - *off = offset as i64; - } else { - return Err(Error::CfiInstructionInInvalidContext); - } - } - DefCfaOffsetSf { factored_offset } => { - if let CfaRule::RegisterAndOffset { - offset: ref mut off, - .. - } = *self.ctx.cfa_mut() - { - let data_align = self.data_alignment_factor; - *off = (Wrapping(factored_offset) * data_align).0; - } else { - return Err(Error::CfiInstructionInInvalidContext); - } - } - DefCfaExpression { expression } => { - self.ctx.set_cfa(CfaRule::Expression(expression)); - } - - // Instructions that define register rules. - Undefined { register } => { - self.ctx - .set_register_rule(register, RegisterRule::Undefined)?; - } - SameValue { register } => { - self.ctx - .set_register_rule(register, RegisterRule::SameValue)?; - } - Offset { - register, - factored_offset, - } => { - let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor; - self.ctx - .set_register_rule(register, RegisterRule::Offset(offset.0))?; - } - OffsetExtendedSf { - register, - factored_offset, - } => { - let offset = Wrapping(factored_offset) * self.data_alignment_factor; - self.ctx - .set_register_rule(register, RegisterRule::Offset(offset.0))?; - } - ValOffset { - register, - factored_offset, - } => { - let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor; - self.ctx - .set_register_rule(register, RegisterRule::ValOffset(offset.0))?; - } - ValOffsetSf { - register, - factored_offset, - } => { - let offset = Wrapping(factored_offset) * self.data_alignment_factor; - self.ctx - .set_register_rule(register, RegisterRule::ValOffset(offset.0))?; - } - Register { - dest_register, - src_register, - } => { - self.ctx - .set_register_rule(dest_register, RegisterRule::Register(src_register))?; - } - Expression { - register, - expression, - } => { - let expression = RegisterRule::Expression(expression); - self.ctx.set_register_rule(register, expression)?; - } - ValExpression { - register, - expression, - } => { - let expression = RegisterRule::ValExpression(expression); - self.ctx.set_register_rule(register, expression)?; - } - Restore { register } => { - let initial_rule = if let Some(rule) = self.ctx.get_initial_rule(register) { - rule - } else { - // Can't restore the initial rule when we are - // evaluating the initial rules! - return Err(Error::CfiInstructionInInvalidContext); - }; - - self.ctx.set_register_rule(register, initial_rule)?; - } - - // Row push and pop instructions. - RememberState => { - self.ctx.push_row()?; - } - RestoreState => { - // Pop state while preserving current location. - let start_address = self.ctx.start_address(); - self.ctx.pop_row()?; - self.ctx.set_start_address(start_address); - } - - // GNU Extension. Save the size somewhere so the unwinder can use - // it when restoring IP - ArgsSize { size } => { - self.ctx.row_mut().saved_args_size = size; - } - - // AArch64 extension. - NegateRaState => { - let register = crate::AArch64::RA_SIGN_STATE; - let value = match self.ctx.row().register(register) { - RegisterRule::Undefined => 0, - RegisterRule::Constant(value) => value, - _ => return Err(Error::CfiInstructionInInvalidContext), - }; - self.ctx - .set_register_rule(register, RegisterRule::Constant(value ^ 1))?; - } - - // No operation. - Nop => {} - }; - - Ok(false) - } -} - -// We tend to have very few register rules: usually only a couple. Even if we -// have a rule for every register, on x86-64 with SSE and everything we're -// talking about ~100 rules. So rather than keeping the rules in a hash map, or -// a vector indexed by register number (which would lead to filling lots of -// empty entries), we store them as a vec of (register number, register rule) -// pairs. -// -// Additionally, because every register's default rule is implicitly -// `RegisterRule::Undefined`, we never store a register's rule in this vec if it -// is undefined and save a little bit more space and do a little fewer -// comparisons that way. -// -// The maximum number of rules preallocated by libunwind is 97 for AArch64, 128 -// for ARM, and even 188 for MIPS. It is extremely unlikely to encounter this -// many register rules in practice. -// -// See: -// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-x86_64/dwarf-config.h#L36 -// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-aarch64/dwarf-config.h#L32 -// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-arm/dwarf-config.h#L31 -// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-mips/dwarf-config.h#L31 -struct RegisterRuleMap<R: Reader, S: UnwindContextStorage<R> = StoreOnHeap> { - rules: ArrayVec<S::Rules>, -} - -impl<R: Reader, S: UnwindContextStorage<R>> Debug for RegisterRuleMap<R, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("RegisterRuleMap") - .field("rules", &self.rules) - .finish() - } -} - -impl<R: Reader, S: UnwindContextStorage<R>> Clone for RegisterRuleMap<R, S> { - fn clone(&self) -> Self { - Self { - rules: self.rules.clone(), - } - } -} - -impl<R: Reader, S: UnwindContextStorage<R>> Default for RegisterRuleMap<R, S> { - fn default() -> Self { - RegisterRuleMap { - rules: Default::default(), - } - } -} - -/// # Signal Safe Methods -/// -/// These methods are guaranteed not to allocate, acquire locks, or perform any -/// other signal-unsafe operations. -impl<R: Reader, S: UnwindContextStorage<R>> RegisterRuleMap<R, S> { - fn is_default(&self) -> bool { - self.rules.is_empty() - } - - fn get(&self, register: Register) -> RegisterRule<R> { - self.rules - .iter() - .find(|rule| rule.0 == register) - .map(|r| { - debug_assert!(r.1.is_defined()); - r.1.clone() - }) - .unwrap_or(RegisterRule::Undefined) - } - - fn set(&mut self, register: Register, rule: RegisterRule<R>) -> Result<()> { - if !rule.is_defined() { - let idx = self - .rules - .iter() - .enumerate() - .find(|&(_, r)| r.0 == register) - .map(|(i, _)| i); - if let Some(idx) = idx { - self.rules.swap_remove(idx); - } - return Ok(()); - } - - for &mut (reg, ref mut old_rule) in &mut *self.rules { - debug_assert!(old_rule.is_defined()); - if reg == register { - *old_rule = rule; - return Ok(()); - } - } - - self.rules - .try_push((register, rule)) - .map_err(|_| Error::TooManyRegisterRules) - } - - fn iter(&self) -> RegisterRuleIter<R> { - RegisterRuleIter(self.rules.iter()) - } -} - -impl<'a, R, S: UnwindContextStorage<R>> FromIterator<&'a (Register, RegisterRule<R>)> - for RegisterRuleMap<R, S> -where - R: 'a + Reader, -{ - fn from_iter<T>(iter: T) -> Self - where - T: IntoIterator<Item = &'a (Register, RegisterRule<R>)>, - { - let iter = iter.into_iter(); - let mut rules = RegisterRuleMap::default(); - for &(reg, ref rule) in iter.filter(|r| r.1.is_defined()) { - rules.set(reg, rule.clone()).expect( - "This is only used in tests, impl isn't exposed publicly. - If you trip this, fix your test", - ); - } - rules - } -} - -impl<R, S: UnwindContextStorage<R>> PartialEq for RegisterRuleMap<R, S> -where - R: Reader + PartialEq, -{ - fn eq(&self, rhs: &Self) -> bool { - for &(reg, ref rule) in &*self.rules { - debug_assert!(rule.is_defined()); - if *rule != rhs.get(reg) { - return false; - } - } - - for &(reg, ref rhs_rule) in &*rhs.rules { - debug_assert!(rhs_rule.is_defined()); - if *rhs_rule != self.get(reg) { - return false; - } - } - - true - } -} - -impl<R, S: UnwindContextStorage<R>> Eq for RegisterRuleMap<R, S> where R: Reader + Eq {} - -/// An unordered iterator for register rules. -#[derive(Debug, Clone)] -pub struct RegisterRuleIter<'iter, R>(::core::slice::Iter<'iter, (Register, RegisterRule<R>)>) -where - R: Reader; - -impl<'iter, R: Reader> Iterator for RegisterRuleIter<'iter, R> { - type Item = &'iter (Register, RegisterRule<R>); - - fn next(&mut self) -> Option<Self::Item> { - self.0.next() - } -} - -/// A row in the virtual unwind table that describes how to find the values of -/// the registers in the *previous* frame for a range of PC addresses. -#[derive(PartialEq, Eq)] -pub struct UnwindTableRow<R: Reader, S: UnwindContextStorage<R> = StoreOnHeap> { - start_address: u64, - end_address: u64, - saved_args_size: u64, - cfa: CfaRule<R>, - registers: RegisterRuleMap<R, S>, -} - -impl<R: Reader, S: UnwindContextStorage<R>> Debug for UnwindTableRow<R, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("UnwindTableRow") - .field("start_address", &self.start_address) - .field("end_address", &self.end_address) - .field("saved_args_size", &self.saved_args_size) - .field("cfa", &self.cfa) - .field("registers", &self.registers) - .finish() - } -} - -impl<R: Reader, S: UnwindContextStorage<R>> Clone for UnwindTableRow<R, S> { - fn clone(&self) -> Self { - Self { - start_address: self.start_address, - end_address: self.end_address, - saved_args_size: self.saved_args_size, - cfa: self.cfa.clone(), - registers: self.registers.clone(), - } - } -} - -impl<R: Reader, S: UnwindContextStorage<R>> Default for UnwindTableRow<R, S> { - fn default() -> Self { - UnwindTableRow { - start_address: 0, - end_address: 0, - saved_args_size: 0, - cfa: Default::default(), - registers: Default::default(), - } - } -} - -impl<R: Reader, S: UnwindContextStorage<R>> UnwindTableRow<R, S> { - fn is_default(&self) -> bool { - self.start_address == 0 - && self.end_address == 0 - && self.cfa.is_default() - && self.registers.is_default() - } - - /// Get the starting PC address that this row applies to. - pub fn start_address(&self) -> u64 { - self.start_address - } - - /// Get the end PC address where this row's register rules become - /// unapplicable. - /// - /// In other words, this row describes how to recover the last frame's - /// registers for all PCs where `row.start_address() <= PC < - /// row.end_address()`. This row does NOT describe how to recover registers - /// when `PC == row.end_address()`. - pub fn end_address(&self) -> u64 { - self.end_address - } - - /// Return `true` if the given `address` is within this row's address range, - /// `false` otherwise. - pub fn contains(&self, address: u64) -> bool { - self.start_address <= address && address < self.end_address - } - - /// Returns the amount of args currently on the stack. - /// - /// When unwinding, if the personality function requested a change in IP, - /// the SP needs to be adjusted by saved_args_size. - pub fn saved_args_size(&self) -> u64 { - self.saved_args_size - } - - /// Get the canonical frame address (CFA) recovery rule for this row. - pub fn cfa(&self) -> &CfaRule<R> { - &self.cfa - } - - /// Get the register recovery rule for the given register number. - /// - /// The register number mapping is architecture dependent. For example, in - /// the x86-64 ABI the register number mapping is defined in Figure 3.36: - /// - /// > Figure 3.36: DWARF Register Number Mapping - /// > - /// > <table> - /// > <tr><th>Register Name</th> <th>Number</th> <th>Abbreviation</th></tr> - /// > <tr><td>General Purpose Register RAX</td> <td>0</td> <td>%rax</td></tr> - /// > <tr><td>General Purpose Register RDX</td> <td>1</td> <td>%rdx</td></tr> - /// > <tr><td>General Purpose Register RCX</td> <td>2</td> <td>%rcx</td></tr> - /// > <tr><td>General Purpose Register RBX</td> <td>3</td> <td>%rbx</td></tr> - /// > <tr><td>General Purpose Register RSI</td> <td>4</td> <td>%rsi</td></tr> - /// > <tr><td>General Purpose Register RDI</td> <td>5</td> <td>%rdi</td></tr> - /// > <tr><td>General Purpose Register RBP</td> <td>6</td> <td>%rbp</td></tr> - /// > <tr><td>Stack Pointer Register RSP</td> <td>7</td> <td>%rsp</td></tr> - /// > <tr><td>Extended Integer Registers 8-15</td> <td>8-15</td> <td>%r8-%r15</td></tr> - /// > <tr><td>Return Address RA</td> <td>16</td> <td></td></tr> - /// > <tr><td>Vector Registers 0–7</td> <td>17-24</td> <td>%xmm0–%xmm7</td></tr> - /// > <tr><td>Extended Vector Registers 8–15</td> <td>25-32</td> <td>%xmm8–%xmm15</td></tr> - /// > <tr><td>Floating Point Registers 0–7</td> <td>33-40</td> <td>%st0–%st7</td></tr> - /// > <tr><td>MMX Registers 0–7</td> <td>41-48</td> <td>%mm0–%mm7</td></tr> - /// > <tr><td>Flag Register</td> <td>49</td> <td>%rFLAGS</td></tr> - /// > <tr><td>Segment Register ES</td> <td>50</td> <td>%es</td></tr> - /// > <tr><td>Segment Register CS</td> <td>51</td> <td>%cs</td></tr> - /// > <tr><td>Segment Register SS</td> <td>52</td> <td>%ss</td></tr> - /// > <tr><td>Segment Register DS</td> <td>53</td> <td>%ds</td></tr> - /// > <tr><td>Segment Register FS</td> <td>54</td> <td>%fs</td></tr> - /// > <tr><td>Segment Register GS</td> <td>55</td> <td>%gs</td></tr> - /// > <tr><td>Reserved</td> <td>56-57</td> <td></td></tr> - /// > <tr><td>FS Base address</td> <td>58</td> <td>%fs.base</td></tr> - /// > <tr><td>GS Base address</td> <td>59</td> <td>%gs.base</td></tr> - /// > <tr><td>Reserved</td> <td>60-61</td> <td></td></tr> - /// > <tr><td>Task Register</td> <td>62</td> <td>%tr</td></tr> - /// > <tr><td>LDT Register</td> <td>63</td> <td>%ldtr</td></tr> - /// > <tr><td>128-bit Media Control and Status</td> <td>64</td> <td>%mxcsr</td></tr> - /// > <tr><td>x87 Control Word</td> <td>65</td> <td>%fcw</td></tr> - /// > <tr><td>x87 Status Word</td> <td>66</td> <td>%fsw</td></tr> - /// > <tr><td>Upper Vector Registers 16–31</td> <td>67-82</td> <td>%xmm16–%xmm31</td></tr> - /// > <tr><td>Reserved</td> <td>83-117</td> <td></td></tr> - /// > <tr><td>Vector Mask Registers 0–7</td> <td>118-125</td> <td>%k0–%k7</td></tr> - /// > <tr><td>Reserved</td> <td>126-129</td> <td></td></tr> - /// > </table> - pub fn register(&self, register: Register) -> RegisterRule<R> { - self.registers.get(register) - } - - /// Iterate over all defined register `(number, rule)` pairs. - /// - /// The rules are not iterated in any guaranteed order. Any register that - /// does not make an appearance in the iterator implicitly has the rule - /// `RegisterRule::Undefined`. - /// - /// ``` - /// # use gimli::{EndianSlice, LittleEndian, UnwindTableRow}; - /// # fn foo<'input>(unwind_table_row: UnwindTableRow<EndianSlice<'input, LittleEndian>>) { - /// for &(register, ref rule) in unwind_table_row.registers() { - /// // ... - /// # drop(register); drop(rule); - /// } - /// # } - /// ``` - pub fn registers(&self) -> RegisterRuleIter<R> { - self.registers.iter() - } -} - -/// The canonical frame address (CFA) recovery rules. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CfaRule<R: Reader> { - /// The CFA is given offset from the given register's value. - RegisterAndOffset { - /// The register containing the base value. - register: Register, - /// The offset from the register's base value. - offset: i64, - }, - /// The CFA is obtained by evaluating this `Reader` as a DWARF expression - /// program. - Expression(Expression<R>), -} - -impl<R: Reader> Default for CfaRule<R> { - fn default() -> Self { - CfaRule::RegisterAndOffset { - register: Register(0), - offset: 0, - } - } -} - -impl<R: Reader> CfaRule<R> { - fn is_default(&self) -> bool { - match *self { - CfaRule::RegisterAndOffset { register, offset } => { - register == Register(0) && offset == 0 - } - _ => false, - } - } -} - -/// An entry in the abstract CFI table that describes how to find the value of a -/// register. -/// -/// "The register columns contain rules that describe whether a given register -/// has been saved and the rule to find the value for the register in the -/// previous frame." -#[derive(Clone, Debug, PartialEq, Eq)] -#[non_exhaustive] -pub enum RegisterRule<R: Reader> { - /// > A register that has this rule has no recoverable value in the previous - /// > frame. (By convention, it is not preserved by a callee.) - Undefined, - - /// > This register has not been modified from the previous frame. (By - /// > convention, it is preserved by the callee, but the callee has not - /// > modified it.) - SameValue, - - /// "The previous value of this register is saved at the address CFA+N where - /// CFA is the current CFA value and N is a signed offset." - Offset(i64), - - /// "The previous value of this register is the value CFA+N where CFA is the - /// current CFA value and N is a signed offset." - ValOffset(i64), - - /// "The previous value of this register is stored in another register - /// numbered R." - Register(Register), - - /// "The previous value of this register is located at the address produced - /// by executing the DWARF expression." - Expression(Expression<R>), - - /// "The previous value of this register is the value produced by executing - /// the DWARF expression." - ValExpression(Expression<R>), - - /// "The rule is defined externally to this specification by the augmenter." - Architectural, - - /// This is a pseudo-register with a constant value. - Constant(u64), -} - -impl<R: Reader> RegisterRule<R> { - fn is_defined(&self) -> bool { - !matches!(*self, RegisterRule::Undefined) - } -} - -/// A parsed call frame instruction. -#[derive(Clone, Debug, PartialEq, Eq)] -#[non_exhaustive] -pub enum CallFrameInstruction<R: Reader> { - // 6.4.2.1 Row Creation Methods - /// > 1. DW_CFA_set_loc - /// > - /// > The DW_CFA_set_loc instruction takes a single operand that represents - /// > a target address. The required action is to create a new table row - /// > using the specified address as the location. All other values in the - /// > new row are initially identical to the current row. The new location - /// > value is always greater than the current one. If the segment_size - /// > field of this FDE's CIE is non- zero, the initial location is preceded - /// > by a segment selector of the given length. - SetLoc { - /// The target address. - address: u64, - }, - - /// The `AdvanceLoc` instruction is used for all of `DW_CFA_advance_loc` and - /// `DW_CFA_advance_loc{1,2,4}`. - /// - /// > 2. DW_CFA_advance_loc - /// > - /// > The DW_CFA_advance instruction takes a single operand (encoded with - /// > the opcode) that represents a constant delta. The required action is - /// > to create a new table row with a location value that is computed by - /// > taking the current entry’s location value and adding the value of - /// > delta * code_alignment_factor. All other values in the new row are - /// > initially identical to the current row. - AdvanceLoc { - /// The delta to be added to the current address. - delta: u32, - }, - - // 6.4.2.2 CFA Definition Methods - /// > 1. DW_CFA_def_cfa - /// > - /// > The DW_CFA_def_cfa instruction takes two unsigned LEB128 operands - /// > representing a register number and a (non-factored) offset. The - /// > required action is to define the current CFA rule to use the provided - /// > register and offset. - DefCfa { - /// The target register's number. - register: Register, - /// The non-factored offset. - offset: u64, - }, - - /// > 2. DW_CFA_def_cfa_sf - /// > - /// > The DW_CFA_def_cfa_sf instruction takes two operands: an unsigned - /// > LEB128 value representing a register number and a signed LEB128 - /// > factored offset. This instruction is identical to DW_CFA_def_cfa - /// > except that the second operand is signed and factored. The resulting - /// > offset is factored_offset * data_alignment_factor. - DefCfaSf { - /// The target register's number. - register: Register, - /// The factored offset. - factored_offset: i64, - }, - - /// > 3. DW_CFA_def_cfa_register - /// > - /// > The DW_CFA_def_cfa_register instruction takes a single unsigned LEB128 - /// > operand representing a register number. The required action is to - /// > define the current CFA rule to use the provided register (but to keep - /// > the old offset). This operation is valid only if the current CFA rule - /// > is defined to use a register and offset. - DefCfaRegister { - /// The target register's number. - register: Register, - }, - - /// > 4. DW_CFA_def_cfa_offset - /// > - /// > The DW_CFA_def_cfa_offset instruction takes a single unsigned LEB128 - /// > operand representing a (non-factored) offset. The required action is - /// > to define the current CFA rule to use the provided offset (but to keep - /// > the old register). This operation is valid only if the current CFA - /// > rule is defined to use a register and offset. - DefCfaOffset { - /// The non-factored offset. - offset: u64, - }, - - /// > 5. DW_CFA_def_cfa_offset_sf - /// > - /// > The DW_CFA_def_cfa_offset_sf instruction takes a signed LEB128 operand - /// > representing a factored offset. This instruction is identical to - /// > DW_CFA_def_cfa_offset except that the operand is signed and - /// > factored. The resulting offset is factored_offset * - /// > data_alignment_factor. This operation is valid only if the current CFA - /// > rule is defined to use a register and offset. - DefCfaOffsetSf { - /// The factored offset. - factored_offset: i64, - }, - - /// > 6. DW_CFA_def_cfa_expression - /// > - /// > The DW_CFA_def_cfa_expression instruction takes a single operand - /// > encoded as a DW_FORM_exprloc value representing a DWARF - /// > expression. The required action is to establish that expression as the - /// > means by which the current CFA is computed. - DefCfaExpression { - /// The DWARF expression. - expression: Expression<R>, - }, - - // 6.4.2.3 Register Rule Instructions - /// > 1. DW_CFA_undefined - /// > - /// > The DW_CFA_undefined instruction takes a single unsigned LEB128 - /// > operand that represents a register number. The required action is to - /// > set the rule for the specified register to “undefined.” - Undefined { - /// The target register's number. - register: Register, - }, - - /// > 2. DW_CFA_same_value - /// > - /// > The DW_CFA_same_value instruction takes a single unsigned LEB128 - /// > operand that represents a register number. The required action is to - /// > set the rule for the specified register to “same value.” - SameValue { - /// The target register's number. - register: Register, - }, - - /// The `Offset` instruction represents both `DW_CFA_offset` and - /// `DW_CFA_offset_extended`. - /// - /// > 3. DW_CFA_offset - /// > - /// > The DW_CFA_offset instruction takes two operands: a register number - /// > (encoded with the opcode) and an unsigned LEB128 constant representing - /// > a factored offset. The required action is to change the rule for the - /// > register indicated by the register number to be an offset(N) rule - /// > where the value of N is factored offset * data_alignment_factor. - Offset { - /// The target register's number. - register: Register, - /// The factored offset. - factored_offset: u64, - }, - - /// > 5. DW_CFA_offset_extended_sf - /// > - /// > The DW_CFA_offset_extended_sf instruction takes two operands: an - /// > unsigned LEB128 value representing a register number and a signed - /// > LEB128 factored offset. This instruction is identical to - /// > DW_CFA_offset_extended except that the second operand is signed and - /// > factored. The resulting offset is factored_offset * - /// > data_alignment_factor. - OffsetExtendedSf { - /// The target register's number. - register: Register, - /// The factored offset. - factored_offset: i64, - }, - - /// > 6. DW_CFA_val_offset - /// > - /// > The DW_CFA_val_offset instruction takes two unsigned LEB128 operands - /// > representing a register number and a factored offset. The required - /// > action is to change the rule for the register indicated by the - /// > register number to be a val_offset(N) rule where the value of N is - /// > factored_offset * data_alignment_factor. - ValOffset { - /// The target register's number. - register: Register, - /// The factored offset. - factored_offset: u64, - }, - - /// > 7. DW_CFA_val_offset_sf - /// > - /// > The DW_CFA_val_offset_sf instruction takes two operands: an unsigned - /// > LEB128 value representing a register number and a signed LEB128 - /// > factored offset. This instruction is identical to DW_CFA_val_offset - /// > except that the second operand is signed and factored. The resulting - /// > offset is factored_offset * data_alignment_factor. - ValOffsetSf { - /// The target register's number. - register: Register, - /// The factored offset. - factored_offset: i64, - }, - - /// > 8. DW_CFA_register - /// > - /// > The DW_CFA_register instruction takes two unsigned LEB128 operands - /// > representing register numbers. The required action is to set the rule - /// > for the first register to be register(R) where R is the second - /// > register. - Register { - /// The number of the register whose rule is being changed. - dest_register: Register, - /// The number of the register where the other register's value can be - /// found. - src_register: Register, - }, - - /// > 9. DW_CFA_expression - /// > - /// > The DW_CFA_expression instruction takes two operands: an unsigned - /// > LEB128 value representing a register number, and a DW_FORM_block value - /// > representing a DWARF expression. The required action is to change the - /// > rule for the register indicated by the register number to be an - /// > expression(E) rule where E is the DWARF expression. That is, the DWARF - /// > expression computes the address. The value of the CFA is pushed on the - /// > DWARF evaluation stack prior to execution of the DWARF expression. - Expression { - /// The target register's number. - register: Register, - /// The DWARF expression. - expression: Expression<R>, - }, - - /// > 10. DW_CFA_val_expression - /// > - /// > The DW_CFA_val_expression instruction takes two operands: an unsigned - /// > LEB128 value representing a register number, and a DW_FORM_block value - /// > representing a DWARF expression. The required action is to change the - /// > rule for the register indicated by the register number to be a - /// > val_expression(E) rule where E is the DWARF expression. That is, the - /// > DWARF expression computes the value of the given register. The value - /// > of the CFA is pushed on the DWARF evaluation stack prior to execution - /// > of the DWARF expression. - ValExpression { - /// The target register's number. - register: Register, - /// The DWARF expression. - expression: Expression<R>, - }, - - /// The `Restore` instruction represents both `DW_CFA_restore` and - /// `DW_CFA_restore_extended`. - /// - /// > 11. DW_CFA_restore - /// > - /// > The DW_CFA_restore instruction takes a single operand (encoded with - /// > the opcode) that represents a register number. The required action is - /// > to change the rule for the indicated register to the rule assigned it - /// > by the initial_instructions in the CIE. - Restore { - /// The register to be reset. - register: Register, - }, - - // 6.4.2.4 Row State Instructions - /// > 1. DW_CFA_remember_state - /// > - /// > The DW_CFA_remember_state instruction takes no operands. The required - /// > action is to push the set of rules for every register onto an implicit - /// > stack. - RememberState, - - /// > 2. DW_CFA_restore_state - /// > - /// > The DW_CFA_restore_state instruction takes no operands. The required - /// > action is to pop the set of rules off the implicit stack and place - /// > them in the current row. - RestoreState, - - /// > DW_CFA_GNU_args_size - /// > - /// > GNU Extension - /// > - /// > The DW_CFA_GNU_args_size instruction takes an unsigned LEB128 operand - /// > representing an argument size. This instruction specifies the total of - /// > the size of the arguments which have been pushed onto the stack. - ArgsSize { - /// The size of the arguments which have been pushed onto the stack - size: u64, - }, - - /// > DW_CFA_AARCH64_negate_ra_state - /// > - /// > AArch64 Extension - /// > - /// > The DW_CFA_AARCH64_negate_ra_state operation negates bit 0 of the - /// > RA_SIGN_STATE pseudo-register. It does not take any operands. The - /// > DW_CFA_AARCH64_negate_ra_state must not be mixed with other DWARF Register - /// > Rule Instructions on the RA_SIGN_STATE pseudo-register in one Common - /// > Information Entry (CIE) and Frame Descriptor Entry (FDE) program sequence. - NegateRaState, - - // 6.4.2.5 Padding Instruction - /// > 1. DW_CFA_nop - /// > - /// > The DW_CFA_nop instruction has no operands and no required actions. It - /// > is used as padding to make a CIE or FDE an appropriate size. - Nop, -} - -const CFI_INSTRUCTION_HIGH_BITS_MASK: u8 = 0b1100_0000; -const CFI_INSTRUCTION_LOW_BITS_MASK: u8 = !CFI_INSTRUCTION_HIGH_BITS_MASK; - -impl<R: Reader> CallFrameInstruction<R> { - fn parse( - input: &mut R, - address_encoding: Option<DwEhPe>, - parameters: &PointerEncodingParameters<R>, - vendor: Vendor, - ) -> Result<CallFrameInstruction<R>> { - let instruction = input.read_u8()?; - let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK; - - if high_bits == constants::DW_CFA_advance_loc.0 { - let delta = instruction & CFI_INSTRUCTION_LOW_BITS_MASK; - return Ok(CallFrameInstruction::AdvanceLoc { - delta: u32::from(delta), - }); - } - - if high_bits == constants::DW_CFA_offset.0 { - let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into()); - let offset = input.read_uleb128()?; - return Ok(CallFrameInstruction::Offset { - register, - factored_offset: offset, - }); - } - - if high_bits == constants::DW_CFA_restore.0 { - let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into()); - return Ok(CallFrameInstruction::Restore { register }); - } - - debug_assert_eq!(high_bits, 0); - let instruction = constants::DwCfa(instruction); - - match instruction { - constants::DW_CFA_nop => Ok(CallFrameInstruction::Nop), - - constants::DW_CFA_set_loc => { - let address = if let Some(encoding) = address_encoding { - parse_encoded_pointer(encoding, parameters, input)?.direct()? - } else { - input.read_address(parameters.address_size)? - }; - Ok(CallFrameInstruction::SetLoc { address }) - } - - constants::DW_CFA_advance_loc1 => { - let delta = input.read_u8()?; - Ok(CallFrameInstruction::AdvanceLoc { - delta: u32::from(delta), - }) - } - - constants::DW_CFA_advance_loc2 => { - let delta = input.read_u16()?; - Ok(CallFrameInstruction::AdvanceLoc { - delta: u32::from(delta), - }) - } - - constants::DW_CFA_advance_loc4 => { - let delta = input.read_u32()?; - Ok(CallFrameInstruction::AdvanceLoc { delta }) - } - - constants::DW_CFA_offset_extended => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - let offset = input.read_uleb128()?; - Ok(CallFrameInstruction::Offset { - register, - factored_offset: offset, - }) - } - - constants::DW_CFA_restore_extended => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - Ok(CallFrameInstruction::Restore { register }) - } - - constants::DW_CFA_undefined => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - Ok(CallFrameInstruction::Undefined { register }) - } - - constants::DW_CFA_same_value => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - Ok(CallFrameInstruction::SameValue { register }) - } - - constants::DW_CFA_register => { - let dest = input.read_uleb128().and_then(Register::from_u64)?; - let src = input.read_uleb128().and_then(Register::from_u64)?; - Ok(CallFrameInstruction::Register { - dest_register: dest, - src_register: src, - }) - } - - constants::DW_CFA_remember_state => Ok(CallFrameInstruction::RememberState), - - constants::DW_CFA_restore_state => Ok(CallFrameInstruction::RestoreState), - - constants::DW_CFA_def_cfa => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - let offset = input.read_uleb128()?; - Ok(CallFrameInstruction::DefCfa { register, offset }) - } - - constants::DW_CFA_def_cfa_register => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - Ok(CallFrameInstruction::DefCfaRegister { register }) - } - - constants::DW_CFA_def_cfa_offset => { - let offset = input.read_uleb128()?; - Ok(CallFrameInstruction::DefCfaOffset { offset }) - } - - constants::DW_CFA_def_cfa_expression => { - let len = input.read_uleb128().and_then(R::Offset::from_u64)?; - let expression = input.split(len)?; - Ok(CallFrameInstruction::DefCfaExpression { - expression: Expression(expression), - }) - } - - constants::DW_CFA_expression => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - let len = input.read_uleb128().and_then(R::Offset::from_u64)?; - let expression = input.split(len)?; - Ok(CallFrameInstruction::Expression { - register, - expression: Expression(expression), - }) - } - - constants::DW_CFA_offset_extended_sf => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - let offset = input.read_sleb128()?; - Ok(CallFrameInstruction::OffsetExtendedSf { - register, - factored_offset: offset, - }) - } - - constants::DW_CFA_def_cfa_sf => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - let offset = input.read_sleb128()?; - Ok(CallFrameInstruction::DefCfaSf { - register, - factored_offset: offset, - }) - } - - constants::DW_CFA_def_cfa_offset_sf => { - let offset = input.read_sleb128()?; - Ok(CallFrameInstruction::DefCfaOffsetSf { - factored_offset: offset, - }) - } - - constants::DW_CFA_val_offset => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - let offset = input.read_uleb128()?; - Ok(CallFrameInstruction::ValOffset { - register, - factored_offset: offset, - }) - } - - constants::DW_CFA_val_offset_sf => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - let offset = input.read_sleb128()?; - Ok(CallFrameInstruction::ValOffsetSf { - register, - factored_offset: offset, - }) - } - - constants::DW_CFA_val_expression => { - let register = input.read_uleb128().and_then(Register::from_u64)?; - let len = input.read_uleb128().and_then(R::Offset::from_u64)?; - let expression = input.split(len)?; - Ok(CallFrameInstruction::ValExpression { - register, - expression: Expression(expression), - }) - } - - constants::DW_CFA_GNU_args_size => { - let size = input.read_uleb128()?; - Ok(CallFrameInstruction::ArgsSize { size }) - } - - constants::DW_CFA_AARCH64_negate_ra_state if vendor == Vendor::AArch64 => { - Ok(CallFrameInstruction::NegateRaState) - } - - otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)), - } - } -} - -/// A lazy iterator parsing call frame instructions. -/// -/// Can be [used with -/// `FallibleIterator`](./index.html#using-with-fallibleiterator). -#[derive(Clone, Debug)] -pub struct CallFrameInstructionIter<'a, R: Reader> { - input: R, - address_encoding: Option<constants::DwEhPe>, - parameters: PointerEncodingParameters<'a, R>, - vendor: Vendor, -} - -impl<'a, R: Reader> CallFrameInstructionIter<'a, R> { - /// Parse the next call frame instruction. - pub fn next(&mut self) -> Result<Option<CallFrameInstruction<R>>> { - if self.input.is_empty() { - return Ok(None); - } - - match CallFrameInstruction::parse( - &mut self.input, - self.address_encoding, - &self.parameters, - self.vendor, - ) { - Ok(instruction) => Ok(Some(instruction)), - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<'a, R: Reader> fallible_iterator::FallibleIterator for CallFrameInstructionIter<'a, R> { - type Item = CallFrameInstruction<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - CallFrameInstructionIter::next(self) - } -} - -/// Parse a `DW_EH_PE_*` pointer encoding. -#[doc(hidden)] -#[inline] -fn parse_pointer_encoding<R: Reader>(input: &mut R) -> Result<constants::DwEhPe> { - let eh_pe = input.read_u8()?; - let eh_pe = constants::DwEhPe(eh_pe); - - if eh_pe.is_valid_encoding() { - Ok(eh_pe) - } else { - Err(Error::UnknownPointerEncoding) - } -} - -/// A decoded pointer. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Pointer { - /// This value is the decoded pointer value. - Direct(u64), - - /// This value is *not* the pointer value, but points to the address of - /// where the real pointer value lives. In other words, deref this pointer - /// to get the real pointer value. - /// - /// Chase this pointer at your own risk: do you trust the DWARF data it came - /// from? - Indirect(u64), -} - -impl Default for Pointer { - #[inline] - fn default() -> Self { - Pointer::Direct(0) - } -} - -impl Pointer { - #[inline] - fn new(encoding: constants::DwEhPe, address: u64) -> Pointer { - if encoding.is_indirect() { - Pointer::Indirect(address) - } else { - Pointer::Direct(address) - } - } - - /// Return the direct pointer value. - #[inline] - pub fn direct(self) -> Result<u64> { - match self { - Pointer::Direct(p) => Ok(p), - Pointer::Indirect(_) => Err(Error::UnsupportedPointerEncoding), - } - } - - /// Return the pointer value, discarding indirectness information. - #[inline] - pub fn pointer(self) -> u64 { - match self { - Pointer::Direct(p) | Pointer::Indirect(p) => p, - } - } -} - -#[derive(Clone, Debug)] -struct PointerEncodingParameters<'a, R: Reader> { - bases: &'a SectionBaseAddresses, - func_base: Option<u64>, - address_size: u8, - section: &'a R, -} - -fn parse_encoded_pointer<R: Reader>( - encoding: constants::DwEhPe, - parameters: &PointerEncodingParameters<R>, - input: &mut R, -) -> Result<Pointer> { - // TODO: check this once only in parse_pointer_encoding - if !encoding.is_valid_encoding() { - return Err(Error::UnknownPointerEncoding); - } - - if encoding == constants::DW_EH_PE_omit { - return Err(Error::CannotParseOmitPointerEncoding); - } - - let base = match encoding.application() { - constants::DW_EH_PE_absptr => 0, - constants::DW_EH_PE_pcrel => { - if let Some(section_base) = parameters.bases.section { - let offset_from_section = input.offset_from(parameters.section); - section_base.wrapping_add(offset_from_section.into_u64()) - } else { - return Err(Error::PcRelativePointerButSectionBaseIsUndefined); - } - } - constants::DW_EH_PE_textrel => { - if let Some(text) = parameters.bases.text { - text - } else { - return Err(Error::TextRelativePointerButTextBaseIsUndefined); - } - } - constants::DW_EH_PE_datarel => { - if let Some(data) = parameters.bases.data { - data - } else { - return Err(Error::DataRelativePointerButDataBaseIsUndefined); - } - } - constants::DW_EH_PE_funcrel => { - if let Some(func) = parameters.func_base { - func - } else { - return Err(Error::FuncRelativePointerInBadContext); - } - } - constants::DW_EH_PE_aligned => return Err(Error::UnsupportedPointerEncoding), - _ => unreachable!(), - }; - - let offset = match encoding.format() { - // Unsigned variants. - constants::DW_EH_PE_absptr => input.read_address(parameters.address_size), - constants::DW_EH_PE_uleb128 => input.read_uleb128(), - constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from), - constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from), - constants::DW_EH_PE_udata8 => input.read_u64(), - - // Signed variants. Here we sign extend the values (happens by - // default when casting a signed integer to a larger range integer - // in Rust), return them as u64, and rely on wrapping addition to do - // the right thing when adding these offsets to their bases. - constants::DW_EH_PE_sleb128 => input.read_sleb128().map(|a| a as u64), - constants::DW_EH_PE_sdata2 => input.read_i16().map(|a| a as u64), - constants::DW_EH_PE_sdata4 => input.read_i32().map(|a| a as u64), - constants::DW_EH_PE_sdata8 => input.read_i64().map(|a| a as u64), - - // That was all of the valid encoding formats. - _ => unreachable!(), - }?; - - Ok(Pointer::new(encoding, base.wrapping_add(offset))) -} - -#[cfg(test)] -mod tests { - use super::*; - use super::{parse_cfi_entry, AugmentationData, RegisterRuleMap, UnwindContext}; - use crate::common::Format; - use crate::constants; - use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian}; - use crate::read::{ - EndianSlice, Error, Expression, Pointer, ReaderOffsetId, Result, Section as ReadSection, - }; - use crate::test_util::GimliSectionMethods; - use alloc::boxed::Box; - use alloc::vec::Vec; - use core::marker::PhantomData; - use core::mem; - use core::u64; - use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum}; - - // Ensure each test tries to read the same section kind that it wrote. - #[derive(Clone, Copy)] - struct SectionKind<Section>(PhantomData<Section>); - - impl<T> SectionKind<T> { - fn endian<'input, E>(self) -> Endian - where - E: Endianity, - T: UnwindSection<EndianSlice<'input, E>>, - T::Offset: UnwindOffset<usize>, - { - if E::default().is_big_endian() { - Endian::Big - } else { - Endian::Little - } - } - - fn section<'input, E>(self, contents: &'input [u8]) -> T - where - E: Endianity, - T: UnwindSection<EndianSlice<'input, E>> + ReadSection<EndianSlice<'input, E>>, - T::Offset: UnwindOffset<usize>, - { - EndianSlice::new(contents, E::default()).into() - } - } - - fn debug_frame_le<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, LittleEndian>>> { - SectionKind(PhantomData) - } - - fn debug_frame_be<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, BigEndian>>> { - SectionKind(PhantomData) - } - - fn eh_frame_le<'a>() -> SectionKind<EhFrame<EndianSlice<'a, LittleEndian>>> { - SectionKind(PhantomData) - } - - fn parse_fde<Section, O, F, R>( - section: Section, - input: &mut R, - get_cie: F, - ) -> Result<FrameDescriptionEntry<R>> - where - R: Reader, - Section: UnwindSection<R, Offset = O>, - O: UnwindOffset<R::Offset>, - F: FnMut(&Section, &BaseAddresses, O) -> Result<CommonInformationEntry<R>>, - { - let bases = Default::default(); - match parse_cfi_entry(&bases, §ion, input) { - Ok(Some(CieOrFde::Fde(partial))) => partial.parse(get_cie), - Ok(_) => Err(Error::NoEntryAtGivenOffset), - Err(e) => Err(e), - } - } - - // Mixin methods for `Section` to help define binary test data. - - trait CfiSectionMethods: GimliSectionMethods { - fn cie<'aug, 'input, E, T>( - self, - _kind: SectionKind<T>, - augmentation: Option<&'aug str>, - cie: &mut CommonInformationEntry<EndianSlice<'input, E>>, - ) -> Self - where - E: Endianity, - T: UnwindSection<EndianSlice<'input, E>>, - T::Offset: UnwindOffset; - fn fde<'a, 'input, E, T, L>( - self, - _kind: SectionKind<T>, - cie_offset: L, - fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>, - ) -> Self - where - E: Endianity, - T: UnwindSection<EndianSlice<'input, E>>, - T::Offset: UnwindOffset, - L: ToLabelOrNum<'a, u64>; - } - - impl CfiSectionMethods for Section { - fn cie<'aug, 'input, E, T>( - self, - _kind: SectionKind<T>, - augmentation: Option<&'aug str>, - cie: &mut CommonInformationEntry<EndianSlice<'input, E>>, - ) -> Self - where - E: Endianity, - T: UnwindSection<EndianSlice<'input, E>>, - T::Offset: UnwindOffset, - { - cie.offset = self.size() as _; - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let section = match cie.format { - Format::Dwarf32 => self.D32(&length).mark(&start).D32(0xffff_ffff), - Format::Dwarf64 => { - let section = self.D32(0xffff_ffff); - section.D64(&length).mark(&start).D64(0xffff_ffff_ffff_ffff) - } - }; - - let mut section = section.D8(cie.version); - - if let Some(augmentation) = augmentation { - section = section.append_bytes(augmentation.as_bytes()); - } - - // Null terminator for augmentation string. - let section = section.D8(0); - - let section = if T::has_address_and_segment_sizes(cie.version) { - section.D8(cie.address_size).D8(cie.segment_size) - } else { - section - }; - - let section = section - .uleb(cie.code_alignment_factor) - .sleb(cie.data_alignment_factor) - .uleb(cie.return_address_register.0.into()) - .append_bytes(cie.initial_instructions.slice()) - .mark(&end); - - cie.length = (&end - &start) as usize; - length.set_const(cie.length as u64); - - section - } - - fn fde<'a, 'input, E, T, L>( - self, - _kind: SectionKind<T>, - cie_offset: L, - fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>, - ) -> Self - where - E: Endianity, - T: UnwindSection<EndianSlice<'input, E>>, - T::Offset: UnwindOffset, - L: ToLabelOrNum<'a, u64>, - { - fde.offset = self.size() as _; - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - assert_eq!(fde.format, fde.cie.format); - - let section = match T::cie_offset_encoding(fde.format) { - CieOffsetEncoding::U32 => { - let section = self.D32(&length).mark(&start); - match cie_offset.to_labelornum() { - LabelOrNum::Label(ref l) => section.D32(l), - LabelOrNum::Num(o) => section.D32(o as u32), - } - } - CieOffsetEncoding::U64 => { - let section = self.D32(0xffff_ffff); - section.D64(&length).mark(&start).D64(cie_offset) - } - }; - - let section = match fde.cie.segment_size { - 0 => section, - 4 => section.D32(fde.initial_segment as u32), - 8 => section.D64(fde.initial_segment), - x => panic!("Unsupported test segment size: {}", x), - }; - - let section = match fde.cie.address_size { - 4 => section - .D32(fde.initial_address() as u32) - .D32(fde.len() as u32), - 8 => section.D64(fde.initial_address()).D64(fde.len()), - x => panic!("Unsupported address size: {}", x), - }; - - let section = if let Some(ref augmentation) = fde.augmentation { - let cie_aug = fde - .cie - .augmentation - .expect("FDE has augmentation, but CIE doesn't"); - - if let Some(lsda) = augmentation.lsda { - // We only support writing `DW_EH_PE_absptr` here. - assert_eq!( - cie_aug - .lsda - .expect("FDE has lsda, but CIE doesn't") - .format(), - constants::DW_EH_PE_absptr - ); - - // Augmentation data length - let section = section.uleb(u64::from(fde.cie.address_size)); - match fde.cie.address_size { - 4 => section.D32({ - let x: u64 = lsda.pointer(); - x as u32 - }), - 8 => section.D64({ - let x: u64 = lsda.pointer(); - x - }), - x => panic!("Unsupported address size: {}", x), - } - } else { - // Even if we don't have any augmentation data, if there is - // an augmentation defined, we need to put the length in. - section.uleb(0) - } - } else { - section - }; - - let section = section.append_bytes(fde.instructions.slice()).mark(&end); - - fde.length = (&end - &start) as usize; - length.set_const(fde.length as u64); - - section - } - } - - trait ResultExt { - fn map_eof(self, input: &[u8]) -> Self; - } - - impl<T> ResultExt for Result<T> { - fn map_eof(self, input: &[u8]) -> Self { - match self { - Err(Error::UnexpectedEof(id)) => { - let id = ReaderOffsetId(id.0 - input.as_ptr() as u64); - Err(Error::UnexpectedEof(id)) - } - r => r, - } - } - } - - fn assert_parse_cie<'input, E>( - kind: SectionKind<DebugFrame<EndianSlice<'input, E>>>, - section: Section, - address_size: u8, - expected: Result<( - EndianSlice<'input, E>, - CommonInformationEntry<EndianSlice<'input, E>>, - )>, - ) where - E: Endianity, - { - let section = section.get_contents().unwrap(); - let mut debug_frame = kind.section(§ion); - debug_frame.set_address_size(address_size); - let input = &mut EndianSlice::new(§ion, E::default()); - let bases = Default::default(); - let result = CommonInformationEntry::parse(&bases, &debug_frame, input); - let result = result.map(|cie| (*input, cie)).map_eof(§ion); - assert_eq!(result, expected); - } - - #[test] - fn test_parse_cie_incomplete_length_32() { - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()).L16(5); - assert_parse_cie( - kind, - section, - 8, - Err(Error::UnexpectedEof(ReaderOffsetId(0))), - ); - } - - #[test] - fn test_parse_cie_incomplete_length_64() { - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - .L32(0xffff_ffff) - .L32(12345); - assert_parse_cie( - kind, - section, - 8, - Err(Error::UnexpectedEof(ReaderOffsetId(4))), - ); - } - - #[test] - fn test_parse_cie_incomplete_id_32() { - let kind = debug_frame_be(); - let section = Section::with_endian(kind.endian()) - // The length is not large enough to contain the ID. - .B32(3) - .B32(0xffff_ffff); - assert_parse_cie( - kind, - section, - 8, - Err(Error::UnexpectedEof(ReaderOffsetId(4))), - ); - } - - #[test] - fn test_parse_cie_bad_id_32() { - let kind = debug_frame_be(); - let section = Section::with_endian(kind.endian()) - // Initial length - .B32(4) - // Not the CIE Id. - .B32(0xbad1_bad2); - assert_parse_cie(kind, section, 8, Err(Error::NotCieId)); - } - - #[test] - fn test_parse_cie_32_bad_version() { - let mut cie = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 99, - augmentation: None, - address_size: 4, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 2, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&[], LittleEndian), - }; - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie); - assert_parse_cie(kind, section, 4, Err(Error::UnknownVersion(99))); - } - - #[test] - fn test_parse_cie_unknown_augmentation() { - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let augmentation = Some("replicant"); - let expected_rest = [1, 2, 3]; - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - // Initial length - .L32(&length) - .mark(&start) - // CIE Id - .L32(0xffff_ffff) - // Version - .D8(4) - // Augmentation - .append_bytes(augmentation.unwrap().as_bytes()) - // Null terminator - .D8(0) - // Extra augmented data that we can't understand. - .L32(1) - .L32(2) - .L32(3) - .L32(4) - .L32(5) - .L32(6) - .mark(&end) - .append_bytes(&expected_rest); - - let expected_length = (&end - &start) as u64; - length.set_const(expected_length); - - assert_parse_cie(kind, section, 8, Err(Error::UnknownAugmentation)); - } - - fn test_parse_cie(format: Format, version: u8, address_size: u8) { - let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); - - let mut cie = CommonInformationEntry { - offset: 0, - length: 0, - format, - version, - augmentation: None, - address_size, - segment_size: 0, - code_alignment_factor: 16, - data_alignment_factor: 32, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian), - }; - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - .cie(kind, None, &mut cie) - .append_bytes(&expected_rest); - - assert_parse_cie( - kind, - section, - address_size, - Ok((EndianSlice::new(&expected_rest, LittleEndian), cie)), - ); - } - - #[test] - fn test_parse_cie_32_ok() { - test_parse_cie(Format::Dwarf32, 1, 4); - test_parse_cie(Format::Dwarf32, 1, 8); - test_parse_cie(Format::Dwarf32, 4, 4); - test_parse_cie(Format::Dwarf32, 4, 8); - } - - #[test] - fn test_parse_cie_64_ok() { - test_parse_cie(Format::Dwarf64, 1, 4); - test_parse_cie(Format::Dwarf64, 1, 8); - test_parse_cie(Format::Dwarf64, 4, 4); - test_parse_cie(Format::Dwarf64, 4, 8); - } - - #[test] - fn test_parse_cie_length_too_big() { - let expected_instrs: Vec<_> = (0..13).map(|_| constants::DW_CFA_nop.0).collect(); - - let mut cie = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 0, - code_alignment_factor: 0, - data_alignment_factor: 0, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian), - }; - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie); - - let mut contents = section.get_contents().unwrap(); - - // Overwrite the length to be too big. - contents[0] = 0; - contents[1] = 0; - contents[2] = 0; - contents[3] = 255; - - let debug_frame = DebugFrame::new(&contents, LittleEndian); - let bases = Default::default(); - assert_eq!( - CommonInformationEntry::parse( - &bases, - &debug_frame, - &mut EndianSlice::new(&contents, LittleEndian) - ) - .map_eof(&contents), - Err(Error::UnexpectedEof(ReaderOffsetId(4))) - ); - } - - #[test] - fn test_parse_fde_incomplete_length_32() { - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()).L16(5); - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, LittleEndian); - assert_eq!( - parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), - Err(Error::UnexpectedEof(ReaderOffsetId(0))) - ); - } - - #[test] - fn test_parse_fde_incomplete_length_64() { - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - .L32(0xffff_ffff) - .L32(12345); - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, LittleEndian); - assert_eq!( - parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), - Err(Error::UnexpectedEof(ReaderOffsetId(4))) - ); - } - - #[test] - fn test_parse_fde_incomplete_cie_pointer_32() { - let kind = debug_frame_be(); - let section = Section::with_endian(kind.endian()) - // The length is not large enough to contain the CIE pointer. - .B32(3) - .B32(1994); - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, BigEndian); - assert_eq!( - parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), - Err(Error::UnexpectedEof(ReaderOffsetId(4))) - ); - } - - #[test] - fn test_parse_fde_32_ok() { - let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let cie_offset = 0xbad0_bad1; - let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect(); - - let cie = CommonInformationEntry { - offset: 0, - length: 100, - format: Format::Dwarf32, - version: 4, - augmentation: None, - // DWARF32 with a 64 bit address size! Holy moly! - address_size: 8, - segment_size: 0, - code_alignment_factor: 3, - data_alignment_factor: 2, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&[], LittleEndian), - }; - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_beef, - address_range: 39, - augmentation: None, - instructions: EndianSlice::new(&expected_instrs, LittleEndian), - }; - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&expected_rest); - - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, LittleEndian); - - let get_cie = |_: &_, _: &_, offset| { - assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); - Ok(cie.clone()) - }; - - assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); - assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_fde_32_with_segment_ok() { - let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let cie_offset = 0xbad0_bad1; - let expected_instrs: Vec<_> = (0..92).map(|_| constants::DW_CFA_nop.0).collect(); - - let cie = CommonInformationEntry { - offset: 0, - length: 100, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 4, - code_alignment_factor: 3, - data_alignment_factor: 2, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&[], LittleEndian), - }; - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0xbadb_ad11, - initial_address: 0xfeed_beef, - address_range: 999, - augmentation: None, - instructions: EndianSlice::new(&expected_instrs, LittleEndian), - }; - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&expected_rest); - - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, LittleEndian); - - let get_cie = |_: &_, _: &_, offset| { - assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); - Ok(cie.clone()) - }; - - assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); - assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_fde_64_ok() { - let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let cie_offset = 0xbad0_bad1; - let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect(); - - let cie = CommonInformationEntry { - offset: 0, - length: 100, - format: Format::Dwarf64, - version: 4, - augmentation: None, - address_size: 8, - segment_size: 0, - code_alignment_factor: 3, - data_alignment_factor: 2, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&[], LittleEndian), - }; - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf64, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_beef, - address_range: 999, - augmentation: None, - instructions: EndianSlice::new(&expected_instrs, LittleEndian), - }; - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&expected_rest); - - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, LittleEndian); - - let get_cie = |_: &_, _: &_, offset| { - assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); - Ok(cie.clone()) - }; - - assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); - assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_entry_on_cie_32_ok() { - let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); - - let mut cie = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 0, - code_alignment_factor: 16, - data_alignment_factor: 32, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&expected_instrs, BigEndian), - }; - - let kind = debug_frame_be(); - let section = Section::with_endian(kind.endian()) - .cie(kind, None, &mut cie) - .append_bytes(&expected_rest); - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, BigEndian); - - let bases = Default::default(); - assert_eq!( - parse_cfi_entry(&bases, &debug_frame, rest), - Ok(Some(CieOrFde::Cie(cie))) - ); - assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian)); - } - - #[test] - fn test_parse_cfi_entry_on_fde_32_ok() { - let cie_offset = 0x1234_5678; - let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); - - let cie = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 0, - code_alignment_factor: 16, - data_alignment_factor: 32, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&[], BigEndian), - }; - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_beef, - address_range: 39, - augmentation: None, - instructions: EndianSlice::new(&expected_instrs, BigEndian), - }; - - let kind = debug_frame_be(); - let section = Section::with_endian(kind.endian()) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&expected_rest); - - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, BigEndian); - - let bases = Default::default(); - match parse_cfi_entry(&bases, &debug_frame, rest) { - Ok(Some(CieOrFde::Fde(partial))) => { - assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian)); - - assert_eq!(partial.length, fde.length); - assert_eq!(partial.format, fde.format); - assert_eq!(partial.cie_offset, DebugFrameOffset(cie_offset as usize)); - - let get_cie = |_: &_, _: &_, offset| { - assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); - Ok(cie.clone()) - }; - - assert_eq!(partial.parse(get_cie), Ok(fde)); - } - otherwise => panic!("Unexpected result: {:#?}", otherwise), - } - } - - #[test] - fn test_cfi_entries_iter() { - let expected_instrs1: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); - - let expected_instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect(); - - let expected_instrs3: Vec<_> = (0..12).map(|_| constants::DW_CFA_nop.0).collect(); - - let expected_instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect(); - - let mut cie1 = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 2, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&expected_instrs1, BigEndian), - }; - - let mut cie2 = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 0, - code_alignment_factor: 3, - data_alignment_factor: 2, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&expected_instrs2, BigEndian), - }; - - let cie1_location = Label::new(); - let cie2_location = Label::new(); - - // Write the CIEs first so that their length gets set before we clone - // them into the FDEs and our equality assertions down the line end up - // with all the CIEs always having he correct length. - let kind = debug_frame_be(); - let section = Section::with_endian(kind.endian()) - .mark(&cie1_location) - .cie(kind, None, &mut cie1) - .mark(&cie2_location) - .cie(kind, None, &mut cie2); - - let mut fde1 = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie1.clone(), - initial_segment: 0, - initial_address: 0xfeed_beef, - address_range: 39, - augmentation: None, - instructions: EndianSlice::new(&expected_instrs3, BigEndian), - }; - - let mut fde2 = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie2.clone(), - initial_segment: 0, - initial_address: 0xfeed_face, - address_range: 9000, - augmentation: None, - instructions: EndianSlice::new(&expected_instrs4, BigEndian), - }; - - let section = - section - .fde(kind, &cie1_location, &mut fde1) - .fde(kind, &cie2_location, &mut fde2); - - section.start().set_const(0); - - let cie1_offset = cie1_location.value().unwrap() as usize; - let cie2_offset = cie2_location.value().unwrap() as usize; - - let contents = section.get_contents().unwrap(); - let debug_frame = kind.section(&contents); - - let bases = Default::default(); - let mut entries = debug_frame.entries(&bases); - - assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie1.clone())))); - assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie2.clone())))); - - match entries.next() { - Ok(Some(CieOrFde::Fde(partial))) => { - assert_eq!(partial.length, fde1.length); - assert_eq!(partial.format, fde1.format); - assert_eq!(partial.cie_offset, DebugFrameOffset(cie1_offset)); - - let get_cie = |_: &_, _: &_, offset| { - assert_eq!(offset, DebugFrameOffset(cie1_offset)); - Ok(cie1.clone()) - }; - assert_eq!(partial.parse(get_cie), Ok(fde1)); - } - otherwise => panic!("Unexpected result: {:#?}", otherwise), - } - - match entries.next() { - Ok(Some(CieOrFde::Fde(partial))) => { - assert_eq!(partial.length, fde2.length); - assert_eq!(partial.format, fde2.format); - assert_eq!(partial.cie_offset, DebugFrameOffset(cie2_offset)); - - let get_cie = |_: &_, _: &_, offset| { - assert_eq!(offset, DebugFrameOffset(cie2_offset)); - Ok(cie2.clone()) - }; - assert_eq!(partial.parse(get_cie), Ok(fde2)); - } - otherwise => panic!("Unexpected result: {:#?}", otherwise), - } - - assert_eq!(entries.next(), Ok(None)); - } - - #[test] - fn test_parse_cie_from_offset() { - let filler = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let instrs: Vec<_> = (0..5).map(|_| constants::DW_CFA_nop.0).collect(); - - let mut cie = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf64, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 0, - code_alignment_factor: 4, - data_alignment_factor: 8, - return_address_register: Register(12), - initial_instructions: EndianSlice::new(&instrs, LittleEndian), - }; - - let cie_location = Label::new(); - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - .append_bytes(&filler) - .mark(&cie_location) - .cie(kind, None, &mut cie) - .append_bytes(&filler); - - section.start().set_const(0); - - let cie_offset = DebugFrameOffset(cie_location.value().unwrap() as usize); - - let contents = section.get_contents().unwrap(); - let debug_frame = kind.section(&contents); - let bases = Default::default(); - - assert_eq!(debug_frame.cie_from_offset(&bases, cie_offset), Ok(cie)); - } - - fn parse_cfi_instruction<R: Reader + Default>( - input: &mut R, - address_size: u8, - ) -> Result<CallFrameInstruction<R>> { - let parameters = &PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size, - section: &R::default(), - }; - CallFrameInstruction::parse(input, None, parameters, Vendor::Default) - } - - #[test] - fn test_parse_cfi_instruction_advance_loc() { - let expected_rest = [1, 2, 3, 4]; - let expected_delta = 42; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_advance_loc.0 | expected_delta) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::AdvanceLoc { - delta: u32::from(expected_delta), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_offset() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 3; - let expected_offset = 1997; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_offset.0 | expected_reg) - .uleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::Offset { - register: Register(expected_reg.into()), - factored_offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_restore() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 3; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_restore.0 | expected_reg) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::Restore { - register: Register(expected_reg.into()), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_nop() { - let expected_rest = [1, 2, 3, 4]; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_nop.0) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::Nop) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_set_loc() { - let expected_rest = [1, 2, 3, 4]; - let expected_addr = 0xdead_beef; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_set_loc.0) - .L64(expected_addr) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::SetLoc { - address: expected_addr, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_set_loc_encoding() { - let text_base = 0xfeed_face; - let addr_offset = 0xbeef; - let expected_addr = text_base + addr_offset; - let expected_rest = [1, 2, 3, 4]; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_set_loc.0) - .L64(addr_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - let parameters = &PointerEncodingParameters { - bases: &BaseAddresses::default().set_text(text_base).eh_frame, - func_base: None, - address_size: 8, - section: &EndianSlice::new(&[], LittleEndian), - }; - assert_eq!( - CallFrameInstruction::parse( - input, - Some(constants::DW_EH_PE_textrel), - parameters, - Vendor::Default - ), - Ok(CallFrameInstruction::SetLoc { - address: expected_addr, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_advance_loc1() { - let expected_rest = [1, 2, 3, 4]; - let expected_delta = 8; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_advance_loc1.0) - .D8(expected_delta) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::AdvanceLoc { - delta: u32::from(expected_delta), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_advance_loc2() { - let expected_rest = [1, 2, 3, 4]; - let expected_delta = 500; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_advance_loc2.0) - .L16(expected_delta) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::AdvanceLoc { - delta: u32::from(expected_delta), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_advance_loc4() { - let expected_rest = [1, 2, 3, 4]; - let expected_delta = 1 << 20; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_advance_loc4.0) - .L32(expected_delta) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::AdvanceLoc { - delta: expected_delta, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_offset_extended() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 7; - let expected_offset = 33; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_offset_extended.0) - .uleb(expected_reg.into()) - .uleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::Offset { - register: Register(expected_reg), - factored_offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_restore_extended() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 7; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_restore_extended.0) - .uleb(expected_reg.into()) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::Restore { - register: Register(expected_reg), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_undefined() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 7; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_undefined.0) - .uleb(expected_reg.into()) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::Undefined { - register: Register(expected_reg), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_same_value() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 7; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_same_value.0) - .uleb(expected_reg.into()) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::SameValue { - register: Register(expected_reg), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_register() { - let expected_rest = [1, 2, 3, 4]; - let expected_dest_reg = 7; - let expected_src_reg = 8; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_register.0) - .uleb(expected_dest_reg.into()) - .uleb(expected_src_reg.into()) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::Register { - dest_register: Register(expected_dest_reg), - src_register: Register(expected_src_reg), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_remember_state() { - let expected_rest = [1, 2, 3, 4]; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_remember_state.0) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::RememberState) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_restore_state() { - let expected_rest = [1, 2, 3, 4]; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_restore_state.0) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::RestoreState) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_def_cfa() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 2; - let expected_offset = 0; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_def_cfa.0) - .uleb(expected_reg.into()) - .uleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::DefCfa { - register: Register(expected_reg), - offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_def_cfa_register() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 2; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_def_cfa_register.0) - .uleb(expected_reg.into()) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::DefCfaRegister { - register: Register(expected_reg), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_def_cfa_offset() { - let expected_rest = [1, 2, 3, 4]; - let expected_offset = 23; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_def_cfa_offset.0) - .uleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::DefCfaOffset { - offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_def_cfa_expression() { - let expected_rest = [1, 2, 3, 4]; - let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; - - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_def_cfa_expression.0) - .D8(&length) - .mark(&start) - .append_bytes(&expected_expr) - .mark(&end) - .append_bytes(&expected_rest); - - length.set_const((&end - &start) as u64); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::DefCfaExpression { - expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_expression() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 99; - let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; - - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_expression.0) - .uleb(expected_reg.into()) - .D8(&length) - .mark(&start) - .append_bytes(&expected_expr) - .mark(&end) - .append_bytes(&expected_rest); - - length.set_const((&end - &start) as u64); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::Expression { - register: Register(expected_reg), - expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_offset_extended_sf() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 7; - let expected_offset = -33; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_offset_extended_sf.0) - .uleb(expected_reg.into()) - .sleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::OffsetExtendedSf { - register: Register(expected_reg), - factored_offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_def_cfa_sf() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 2; - let expected_offset = -9999; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_def_cfa_sf.0) - .uleb(expected_reg.into()) - .sleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::DefCfaSf { - register: Register(expected_reg), - factored_offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_def_cfa_offset_sf() { - let expected_rest = [1, 2, 3, 4]; - let expected_offset = -123; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_def_cfa_offset_sf.0) - .sleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::DefCfaOffsetSf { - factored_offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_val_offset() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 50; - let expected_offset = 23; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_val_offset.0) - .uleb(expected_reg.into()) - .uleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::ValOffset { - register: Register(expected_reg), - factored_offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_val_offset_sf() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 50; - let expected_offset = -23; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_val_offset_sf.0) - .uleb(expected_reg.into()) - .sleb(expected_offset) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::ValOffsetSf { - register: Register(expected_reg), - factored_offset: expected_offset, - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_val_expression() { - let expected_rest = [1, 2, 3, 4]; - let expected_reg = 50; - let expected_expr = [2, 2, 1, 1, 5, 5]; - - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_val_expression.0) - .uleb(expected_reg.into()) - .D8(&length) - .mark(&start) - .append_bytes(&expected_expr) - .mark(&end) - .append_bytes(&expected_rest); - - length.set_const((&end - &start) as u64); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - - assert_eq!( - parse_cfi_instruction(input, 8), - Ok(CallFrameInstruction::ValExpression { - register: Register(expected_reg), - expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)), - }) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_negate_ra_state() { - let expected_rest = [1, 2, 3, 4]; - let section = Section::with_endian(Endian::Little) - .D8(constants::DW_CFA_AARCH64_negate_ra_state.0) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - let parameters = &PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 8, - section: &EndianSlice::default(), - }; - assert_eq!( - CallFrameInstruction::parse(input, None, parameters, Vendor::AArch64), - Ok(CallFrameInstruction::NegateRaState) - ); - assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_cfi_instruction_unknown_instruction() { - let expected_rest = [1, 2, 3, 4]; - let unknown_instr = constants::DwCfa(0b0011_1111); - let section = Section::with_endian(Endian::Little) - .D8(unknown_instr.0) - .append_bytes(&expected_rest); - let contents = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&contents, LittleEndian); - assert_eq!( - parse_cfi_instruction(input, 8), - Err(Error::UnknownCallFrameInstruction(unknown_instr)) - ); - } - - #[test] - fn test_call_frame_instruction_iter_ok() { - let expected_reg = 50; - let expected_expr = [2, 2, 1, 1, 5, 5]; - let expected_delta = 230; - - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let section = Section::with_endian(Endian::Big) - .D8(constants::DW_CFA_val_expression.0) - .uleb(expected_reg.into()) - .D8(&length) - .mark(&start) - .append_bytes(&expected_expr) - .mark(&end) - .D8(constants::DW_CFA_advance_loc1.0) - .D8(expected_delta); - - length.set_const((&end - &start) as u64); - let contents = section.get_contents().unwrap(); - let input = EndianSlice::new(&contents, BigEndian); - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 8, - section: &EndianSlice::default(), - }; - let mut iter = CallFrameInstructionIter { - input, - address_encoding: None, - parameters, - vendor: Vendor::Default, - }; - - assert_eq!( - iter.next(), - Ok(Some(CallFrameInstruction::ValExpression { - register: Register(expected_reg), - expression: Expression(EndianSlice::new(&expected_expr, BigEndian)), - })) - ); - - assert_eq!( - iter.next(), - Ok(Some(CallFrameInstruction::AdvanceLoc { - delta: u32::from(expected_delta), - })) - ); - - assert_eq!(iter.next(), Ok(None)); - } - - #[test] - fn test_call_frame_instruction_iter_err() { - // DW_CFA_advance_loc1 without an operand. - let section = Section::with_endian(Endian::Big).D8(constants::DW_CFA_advance_loc1.0); - - let contents = section.get_contents().unwrap(); - let input = EndianSlice::new(&contents, BigEndian); - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 8, - section: &EndianSlice::default(), - }; - let mut iter = CallFrameInstructionIter { - input, - address_encoding: None, - parameters, - vendor: Vendor::Default, - }; - - assert_eq!( - iter.next().map_eof(&contents), - Err(Error::UnexpectedEof(ReaderOffsetId(1))) - ); - assert_eq!(iter.next(), Ok(None)); - } - - fn assert_eval<'a, I>( - mut initial_ctx: UnwindContext<EndianSlice<'a, LittleEndian>>, - expected_ctx: UnwindContext<EndianSlice<'a, LittleEndian>>, - cie: CommonInformationEntry<EndianSlice<'a, LittleEndian>>, - fde: Option<FrameDescriptionEntry<EndianSlice<'a, LittleEndian>>>, - instructions: I, - ) where - I: AsRef< - [( - Result<bool>, - CallFrameInstruction<EndianSlice<'a, LittleEndian>>, - )], - >, - { - { - let section = &DebugFrame::from(EndianSlice::default()); - let bases = &BaseAddresses::default(); - let mut table = match fde { - Some(fde) => UnwindTable::new_for_fde(section, bases, &mut initial_ctx, &fde), - None => UnwindTable::new_for_cie(section, bases, &mut initial_ctx, &cie), - }; - for &(ref expected_result, ref instruction) in instructions.as_ref() { - assert_eq!(*expected_result, table.evaluate(instruction.clone())); - } - } - - assert_eq!(expected_ctx, initial_ctx); - } - - fn make_test_cie<'a>() -> CommonInformationEntry<EndianSlice<'a, LittleEndian>> { - CommonInformationEntry { - offset: 0, - format: Format::Dwarf64, - length: 0, - return_address_register: Register(0), - version: 4, - address_size: mem::size_of::<usize>() as u8, - initial_instructions: EndianSlice::new(&[], LittleEndian), - augmentation: None, - segment_size: 0, - data_alignment_factor: 2, - code_alignment_factor: 3, - } - } - - #[test] - fn test_eval_set_loc() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected.row_mut().end_address = 42; - let instructions = [(Ok(true), CallFrameInstruction::SetLoc { address: 42 })]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_set_loc_backwards() { - let cie = make_test_cie(); - let mut ctx = UnwindContext::new(); - ctx.row_mut().start_address = 999; - let expected = ctx.clone(); - let instructions = [( - Err(Error::InvalidAddressRange), - CallFrameInstruction::SetLoc { address: 42 }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_advance_loc() { - let cie = make_test_cie(); - let mut ctx = UnwindContext::new(); - ctx.row_mut().start_address = 3; - let mut expected = ctx.clone(); - expected.row_mut().end_address = 3 + 2 * cie.code_alignment_factor; - let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 2 })]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_advance_loc_overflow() { - let cie = make_test_cie(); - let mut ctx = UnwindContext::new(); - ctx.row_mut().start_address = u64::MAX; - let mut expected = ctx.clone(); - expected.row_mut().end_address = 42 * cie.code_alignment_factor - 1; - let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 42 })]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_def_cfa() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected.set_cfa(CfaRule::RegisterAndOffset { - register: Register(42), - offset: 36, - }); - let instructions = [( - Ok(false), - CallFrameInstruction::DefCfa { - register: Register(42), - offset: 36, - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_def_cfa_sf() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected.set_cfa(CfaRule::RegisterAndOffset { - register: Register(42), - offset: 36 * cie.data_alignment_factor as i64, - }); - let instructions = [( - Ok(false), - CallFrameInstruction::DefCfaSf { - register: Register(42), - factored_offset: 36, - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_def_cfa_register() { - let cie = make_test_cie(); - let mut ctx = UnwindContext::new(); - ctx.set_cfa(CfaRule::RegisterAndOffset { - register: Register(3), - offset: 8, - }); - let mut expected = ctx.clone(); - expected.set_cfa(CfaRule::RegisterAndOffset { - register: Register(42), - offset: 8, - }); - let instructions = [( - Ok(false), - CallFrameInstruction::DefCfaRegister { - register: Register(42), - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_def_cfa_register_invalid_context() { - let cie = make_test_cie(); - let mut ctx = UnwindContext::new(); - ctx.set_cfa(CfaRule::Expression(Expression(EndianSlice::new( - &[], - LittleEndian, - )))); - let expected = ctx.clone(); - let instructions = [( - Err(Error::CfiInstructionInInvalidContext), - CallFrameInstruction::DefCfaRegister { - register: Register(42), - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_def_cfa_offset() { - let cie = make_test_cie(); - let mut ctx = UnwindContext::new(); - ctx.set_cfa(CfaRule::RegisterAndOffset { - register: Register(3), - offset: 8, - }); - let mut expected = ctx.clone(); - expected.set_cfa(CfaRule::RegisterAndOffset { - register: Register(3), - offset: 42, - }); - let instructions = [(Ok(false), CallFrameInstruction::DefCfaOffset { offset: 42 })]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_def_cfa_offset_invalid_context() { - let cie = make_test_cie(); - let mut ctx = UnwindContext::new(); - ctx.set_cfa(CfaRule::Expression(Expression(EndianSlice::new( - &[], - LittleEndian, - )))); - let expected = ctx.clone(); - let instructions = [( - Err(Error::CfiInstructionInInvalidContext), - CallFrameInstruction::DefCfaOffset { offset: 1993 }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_def_cfa_expression() { - let expr = [1, 2, 3, 4]; - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected.set_cfa(CfaRule::Expression(Expression(EndianSlice::new( - &expr, - LittleEndian, - )))); - let instructions = [( - Ok(false), - CallFrameInstruction::DefCfaExpression { - expression: Expression(EndianSlice::new(&expr, LittleEndian)), - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_undefined() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule(Register(5), RegisterRule::Undefined) - .unwrap(); - let instructions = [( - Ok(false), - CallFrameInstruction::Undefined { - register: Register(5), - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_same_value() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule(Register(0), RegisterRule::SameValue) - .unwrap(); - let instructions = [( - Ok(false), - CallFrameInstruction::SameValue { - register: Register(0), - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_offset() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule( - Register(2), - RegisterRule::Offset(3 * cie.data_alignment_factor), - ) - .unwrap(); - let instructions = [( - Ok(false), - CallFrameInstruction::Offset { - register: Register(2), - factored_offset: 3, - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_offset_extended_sf() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule( - Register(4), - RegisterRule::Offset(-3 * cie.data_alignment_factor), - ) - .unwrap(); - let instructions = [( - Ok(false), - CallFrameInstruction::OffsetExtendedSf { - register: Register(4), - factored_offset: -3, - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_val_offset() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule( - Register(5), - RegisterRule::ValOffset(7 * cie.data_alignment_factor), - ) - .unwrap(); - let instructions = [( - Ok(false), - CallFrameInstruction::ValOffset { - register: Register(5), - factored_offset: 7, - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_val_offset_sf() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule( - Register(5), - RegisterRule::ValOffset(-7 * cie.data_alignment_factor), - ) - .unwrap(); - let instructions = [( - Ok(false), - CallFrameInstruction::ValOffsetSf { - register: Register(5), - factored_offset: -7, - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_expression() { - let expr = [1, 2, 3, 4]; - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule( - Register(9), - RegisterRule::Expression(Expression(EndianSlice::new(&expr, LittleEndian))), - ) - .unwrap(); - let instructions = [( - Ok(false), - CallFrameInstruction::Expression { - register: Register(9), - expression: Expression(EndianSlice::new(&expr, LittleEndian)), - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_val_expression() { - let expr = [1, 2, 3, 4]; - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule( - Register(9), - RegisterRule::ValExpression(Expression(EndianSlice::new(&expr, LittleEndian))), - ) - .unwrap(); - let instructions = [( - Ok(false), - CallFrameInstruction::ValExpression { - register: Register(9), - expression: Expression(EndianSlice::new(&expr, LittleEndian)), - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_restore() { - let cie = make_test_cie(); - let fde = FrameDescriptionEntry { - offset: 0, - format: Format::Dwarf64, - length: 0, - address_range: 0, - augmentation: None, - initial_address: 0, - initial_segment: 0, - cie: cie.clone(), - instructions: EndianSlice::new(&[], LittleEndian), - }; - - let mut ctx = UnwindContext::new(); - ctx.set_register_rule(Register(0), RegisterRule::Offset(1)) - .unwrap(); - ctx.save_initial_rules().unwrap(); - let expected = ctx.clone(); - ctx.set_register_rule(Register(0), RegisterRule::Offset(2)) - .unwrap(); - - let instructions = [( - Ok(false), - CallFrameInstruction::Restore { - register: Register(0), - }, - )]; - assert_eval(ctx, expected, cie, Some(fde), instructions); - } - - #[test] - fn test_eval_restore_havent_saved_initial_context() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let expected = ctx.clone(); - let instructions = [( - Err(Error::CfiInstructionInInvalidContext), - CallFrameInstruction::Restore { - register: Register(0), - }, - )]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_remember_state() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected.push_row().unwrap(); - let instructions = [(Ok(false), CallFrameInstruction::RememberState)]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_restore_state() { - let cie = make_test_cie(); - - let mut ctx = UnwindContext::new(); - ctx.set_start_address(1); - ctx.set_register_rule(Register(0), RegisterRule::SameValue) - .unwrap(); - let mut expected = ctx.clone(); - ctx.push_row().unwrap(); - ctx.set_start_address(2); - ctx.set_register_rule(Register(0), RegisterRule::Offset(16)) - .unwrap(); - - // Restore state should preserve current location. - expected.set_start_address(2); - - let instructions = [ - // First one pops just fine. - (Ok(false), CallFrameInstruction::RestoreState), - // Second pop would try to pop out of bounds. - ( - Err(Error::PopWithEmptyStack), - CallFrameInstruction::RestoreState, - ), - ]; - - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_negate_ra_state() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(1)) - .unwrap(); - let instructions = [(Ok(false), CallFrameInstruction::NegateRaState)]; - assert_eval(ctx, expected, cie, None, instructions); - - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(0)) - .unwrap(); - let instructions = [ - (Ok(false), CallFrameInstruction::NegateRaState), - (Ok(false), CallFrameInstruction::NegateRaState), - ]; - assert_eval(ctx, expected, cie, None, instructions); - - // NegateRaState can't be used with other instructions. - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let mut expected = ctx.clone(); - expected - .set_register_rule( - crate::AArch64::RA_SIGN_STATE, - RegisterRule::Offset(cie.data_alignment_factor as i64), - ) - .unwrap(); - let instructions = [ - ( - Ok(false), - CallFrameInstruction::Offset { - register: crate::AArch64::RA_SIGN_STATE, - factored_offset: 1, - }, - ), - ( - Err(Error::CfiInstructionInInvalidContext), - CallFrameInstruction::NegateRaState, - ), - ]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_eval_nop() { - let cie = make_test_cie(); - let ctx = UnwindContext::new(); - let expected = ctx.clone(); - let instructions = [(Ok(false), CallFrameInstruction::Nop)]; - assert_eval(ctx, expected, cie, None, instructions); - } - - #[test] - fn test_unwind_table_cie_no_rule() { - let initial_instructions = Section::with_endian(Endian::Little) - // The CFA is -12 from register 4. - .D8(constants::DW_CFA_def_cfa_sf.0) - .uleb(4) - .sleb(-12) - .append_repeated(constants::DW_CFA_nop.0, 4); - let initial_instructions = initial_instructions.get_contents().unwrap(); - - let cie = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 8, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 1, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian), - }; - - let instructions = Section::with_endian(Endian::Little) - // A bunch of nop padding. - .append_repeated(constants::DW_CFA_nop.0, 8); - let instructions = instructions.get_contents().unwrap(); - - let fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0, - address_range: 100, - augmentation: None, - instructions: EndianSlice::new(&instructions, LittleEndian), - }; - - let section = &DebugFrame::from(EndianSlice::default()); - let bases = &BaseAddresses::default(); - let mut ctx = Box::new(UnwindContext::new()); - - let mut table = fde - .rows(section, bases, &mut ctx) - .expect("Should run initial program OK"); - assert!(table.ctx.is_initialized); - let expected_initial_rule = (Register(0), RegisterRule::Undefined); - assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule)); - - { - let row = table.next_row().expect("Should evaluate first row OK"); - let expected = UnwindTableRow { - start_address: 0, - end_address: 100, - saved_args_size: 0, - cfa: CfaRule::RegisterAndOffset { - register: Register(4), - offset: -12, - }, - registers: [].iter().collect(), - }; - assert_eq!(Some(&expected), row); - } - - // All done! - assert_eq!(Ok(None), table.next_row()); - assert_eq!(Ok(None), table.next_row()); - } - - #[test] - fn test_unwind_table_cie_single_rule() { - let initial_instructions = Section::with_endian(Endian::Little) - // The CFA is -12 from register 4. - .D8(constants::DW_CFA_def_cfa_sf.0) - .uleb(4) - .sleb(-12) - // Register 3 is 4 from the CFA. - .D8(constants::DW_CFA_offset.0 | 3) - .uleb(4) - .append_repeated(constants::DW_CFA_nop.0, 4); - let initial_instructions = initial_instructions.get_contents().unwrap(); - - let cie = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 8, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 1, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian), - }; - - let instructions = Section::with_endian(Endian::Little) - // A bunch of nop padding. - .append_repeated(constants::DW_CFA_nop.0, 8); - let instructions = instructions.get_contents().unwrap(); - - let fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0, - address_range: 100, - augmentation: None, - instructions: EndianSlice::new(&instructions, LittleEndian), - }; - - let section = &DebugFrame::from(EndianSlice::default()); - let bases = &BaseAddresses::default(); - let mut ctx = Box::new(UnwindContext::new()); - - let mut table = fde - .rows(section, bases, &mut ctx) - .expect("Should run initial program OK"); - assert!(table.ctx.is_initialized); - let expected_initial_rule = (Register(3), RegisterRule::Offset(4)); - assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule)); - - { - let row = table.next_row().expect("Should evaluate first row OK"); - let expected = UnwindTableRow { - start_address: 0, - end_address: 100, - saved_args_size: 0, - cfa: CfaRule::RegisterAndOffset { - register: Register(4), - offset: -12, - }, - registers: [(Register(3), RegisterRule::Offset(4))].iter().collect(), - }; - assert_eq!(Some(&expected), row); - } - - // All done! - assert_eq!(Ok(None), table.next_row()); - assert_eq!(Ok(None), table.next_row()); - } - - #[test] - fn test_unwind_table_cie_invalid_rule() { - let initial_instructions1 = Section::with_endian(Endian::Little) - // Test that stack length is reset. - .D8(constants::DW_CFA_remember_state.0) - // Test that stack value is reset (different register from that used later). - .D8(constants::DW_CFA_offset.0 | 4) - .uleb(8) - // Invalid due to missing operands. - .D8(constants::DW_CFA_offset.0); - let initial_instructions1 = initial_instructions1.get_contents().unwrap(); - - let cie1 = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 8, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 1, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&initial_instructions1, LittleEndian), - }; - - let initial_instructions2 = Section::with_endian(Endian::Little) - // Register 3 is 4 from the CFA. - .D8(constants::DW_CFA_offset.0 | 3) - .uleb(4) - .append_repeated(constants::DW_CFA_nop.0, 4); - let initial_instructions2 = initial_instructions2.get_contents().unwrap(); - - let cie2 = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 8, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 1, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&initial_instructions2, LittleEndian), - }; - - let fde1 = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie1.clone(), - initial_segment: 0, - initial_address: 0, - address_range: 100, - augmentation: None, - instructions: EndianSlice::new(&[], LittleEndian), - }; - - let fde2 = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie2.clone(), - initial_segment: 0, - initial_address: 0, - address_range: 100, - augmentation: None, - instructions: EndianSlice::new(&[], LittleEndian), - }; - - let section = &DebugFrame::from(EndianSlice::default()); - let bases = &BaseAddresses::default(); - let mut ctx = Box::new(UnwindContext::new()); - - let table = fde1 - .rows(section, bases, &mut ctx) - .map_eof(&initial_instructions1); - assert_eq!(table.err(), Some(Error::UnexpectedEof(ReaderOffsetId(4)))); - assert!(!ctx.is_initialized); - assert_eq!(ctx.stack.len(), 2); - assert_eq!(ctx.initial_rule, None); - - let _table = fde2 - .rows(section, bases, &mut ctx) - .expect("Should run initial program OK"); - assert!(ctx.is_initialized); - assert_eq!(ctx.stack.len(), 1); - let expected_initial_rule = (Register(3), RegisterRule::Offset(4)); - assert_eq!(ctx.initial_rule, Some(expected_initial_rule)); - } - - #[test] - fn test_unwind_table_next_row() { - let initial_instructions = Section::with_endian(Endian::Little) - // The CFA is -12 from register 4. - .D8(constants::DW_CFA_def_cfa_sf.0) - .uleb(4) - .sleb(-12) - // Register 0 is 8 from the CFA. - .D8(constants::DW_CFA_offset.0 | 0) - .uleb(8) - // Register 3 is 4 from the CFA. - .D8(constants::DW_CFA_offset.0 | 3) - .uleb(4) - .append_repeated(constants::DW_CFA_nop.0, 4); - let initial_instructions = initial_instructions.get_contents().unwrap(); - - let cie = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 8, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 1, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian), - }; - - let instructions = Section::with_endian(Endian::Little) - // Initial instructions form a row, advance the address by 1. - .D8(constants::DW_CFA_advance_loc1.0) - .D8(1) - // Register 0 is -16 from the CFA. - .D8(constants::DW_CFA_offset_extended_sf.0) - .uleb(0) - .sleb(-16) - // Finish this row, advance the address by 32. - .D8(constants::DW_CFA_advance_loc1.0) - .D8(32) - // Register 3 is -4 from the CFA. - .D8(constants::DW_CFA_offset_extended_sf.0) - .uleb(3) - .sleb(-4) - // Finish this row, advance the address by 64. - .D8(constants::DW_CFA_advance_loc1.0) - .D8(64) - // Register 5 is 4 from the CFA. - .D8(constants::DW_CFA_offset.0 | 5) - .uleb(4) - // A bunch of nop padding. - .append_repeated(constants::DW_CFA_nop.0, 8); - let instructions = instructions.get_contents().unwrap(); - - let fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0, - address_range: 100, - augmentation: None, - instructions: EndianSlice::new(&instructions, LittleEndian), - }; - - let section = &DebugFrame::from(EndianSlice::default()); - let bases = &BaseAddresses::default(); - let mut ctx = Box::new(UnwindContext::new()); - - let mut table = fde - .rows(section, bases, &mut ctx) - .expect("Should run initial program OK"); - assert!(table.ctx.is_initialized); - assert!(table.ctx.initial_rule.is_none()); - let expected_initial_rules: RegisterRuleMap<_> = [ - (Register(0), RegisterRule::Offset(8)), - (Register(3), RegisterRule::Offset(4)), - ] - .iter() - .collect(); - assert_eq!(table.ctx.stack[0].registers, expected_initial_rules); - - { - let row = table.next_row().expect("Should evaluate first row OK"); - let expected = UnwindTableRow { - start_address: 0, - end_address: 1, - saved_args_size: 0, - cfa: CfaRule::RegisterAndOffset { - register: Register(4), - offset: -12, - }, - registers: [ - (Register(0), RegisterRule::Offset(8)), - (Register(3), RegisterRule::Offset(4)), - ] - .iter() - .collect(), - }; - assert_eq!(Some(&expected), row); - } - - { - let row = table.next_row().expect("Should evaluate second row OK"); - let expected = UnwindTableRow { - start_address: 1, - end_address: 33, - saved_args_size: 0, - cfa: CfaRule::RegisterAndOffset { - register: Register(4), - offset: -12, - }, - registers: [ - (Register(0), RegisterRule::Offset(-16)), - (Register(3), RegisterRule::Offset(4)), - ] - .iter() - .collect(), - }; - assert_eq!(Some(&expected), row); - } - - { - let row = table.next_row().expect("Should evaluate third row OK"); - let expected = UnwindTableRow { - start_address: 33, - end_address: 97, - saved_args_size: 0, - cfa: CfaRule::RegisterAndOffset { - register: Register(4), - offset: -12, - }, - registers: [ - (Register(0), RegisterRule::Offset(-16)), - (Register(3), RegisterRule::Offset(-4)), - ] - .iter() - .collect(), - }; - assert_eq!(Some(&expected), row); - } - - { - let row = table.next_row().expect("Should evaluate fourth row OK"); - let expected = UnwindTableRow { - start_address: 97, - end_address: 100, - saved_args_size: 0, - cfa: CfaRule::RegisterAndOffset { - register: Register(4), - offset: -12, - }, - registers: [ - (Register(0), RegisterRule::Offset(-16)), - (Register(3), RegisterRule::Offset(-4)), - (Register(5), RegisterRule::Offset(4)), - ] - .iter() - .collect(), - }; - assert_eq!(Some(&expected), row); - } - - // All done! - assert_eq!(Ok(None), table.next_row()); - assert_eq!(Ok(None), table.next_row()); - } - - #[test] - fn test_unwind_info_for_address_ok() { - let instrs1 = Section::with_endian(Endian::Big) - // The CFA is -12 from register 4. - .D8(constants::DW_CFA_def_cfa_sf.0) - .uleb(4) - .sleb(-12); - let instrs1 = instrs1.get_contents().unwrap(); - - let instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect(); - - let instrs3 = Section::with_endian(Endian::Big) - // Initial instructions form a row, advance the address by 100. - .D8(constants::DW_CFA_advance_loc1.0) - .D8(100) - // Register 0 is -16 from the CFA. - .D8(constants::DW_CFA_offset_extended_sf.0) - .uleb(0) - .sleb(-16); - let instrs3 = instrs3.get_contents().unwrap(); - - let instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect(); - - let mut cie1 = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 8, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 1, - return_address_register: Register(3), - initial_instructions: EndianSlice::new(&instrs1, BigEndian), - }; - - let mut cie2 = CommonInformationEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 0, - code_alignment_factor: 1, - data_alignment_factor: 1, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&instrs2, BigEndian), - }; - - let cie1_location = Label::new(); - let cie2_location = Label::new(); - - // Write the CIEs first so that their length gets set before we clone - // them into the FDEs and our equality assertions down the line end up - // with all the CIEs always having he correct length. - let kind = debug_frame_be(); - let section = Section::with_endian(kind.endian()) - .mark(&cie1_location) - .cie(kind, None, &mut cie1) - .mark(&cie2_location) - .cie(kind, None, &mut cie2); - - let mut fde1 = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie1.clone(), - initial_segment: 0, - initial_address: 0xfeed_beef, - address_range: 200, - augmentation: None, - instructions: EndianSlice::new(&instrs3, BigEndian), - }; - - let mut fde2 = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie2.clone(), - initial_segment: 0, - initial_address: 0xfeed_face, - address_range: 9000, - augmentation: None, - instructions: EndianSlice::new(&instrs4, BigEndian), - }; - - let section = - section - .fde(kind, &cie1_location, &mut fde1) - .fde(kind, &cie2_location, &mut fde2); - section.start().set_const(0); - - let contents = section.get_contents().unwrap(); - let debug_frame = kind.section(&contents); - - // Get the second row of the unwind table in `instrs3`. - let bases = Default::default(); - let mut ctx = Box::new(UnwindContext::new()); - let result = debug_frame.unwind_info_for_address( - &bases, - &mut ctx, - 0xfeed_beef + 150, - DebugFrame::cie_from_offset, - ); - assert!(result.is_ok()); - let unwind_info = result.unwrap(); - - assert_eq!( - *unwind_info, - UnwindTableRow { - start_address: fde1.initial_address() + 100, - end_address: fde1.initial_address() + fde1.len(), - saved_args_size: 0, - cfa: CfaRule::RegisterAndOffset { - register: Register(4), - offset: -12, - }, - registers: [(Register(0), RegisterRule::Offset(-16))].iter().collect(), - } - ); - } - - #[test] - fn test_unwind_info_for_address_not_found() { - let debug_frame = DebugFrame::new(&[], NativeEndian); - let bases = Default::default(); - let mut ctx = Box::new(UnwindContext::new()); - let result = debug_frame.unwind_info_for_address( - &bases, - &mut ctx, - 0xbadb_ad99, - DebugFrame::cie_from_offset, - ); - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress); - } - - #[test] - fn test_eh_frame_hdr_unknown_version() { - let bases = BaseAddresses::default(); - let buf = &[42]; - let result = EhFrameHdr::new(buf, NativeEndian).parse(&bases, 8); - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), Error::UnknownVersion(42)); - } - - #[test] - fn test_eh_frame_hdr_omit_ehptr() { - let section = Section::with_endian(Endian::Little) - .L8(1) - .L8(0xff) - .L8(0x03) - .L8(0x0b) - .L32(2) - .L32(10) - .L32(1) - .L32(20) - .L32(2) - .L32(0); - let section = section.get_contents().unwrap(); - let bases = BaseAddresses::default(); - let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), Error::CannotParseOmitPointerEncoding); - } - - #[test] - fn test_eh_frame_hdr_omit_count() { - let section = Section::with_endian(Endian::Little) - .L8(1) - .L8(0x0b) - .L8(0xff) - .L8(0x0b) - .L32(0x12345); - let section = section.get_contents().unwrap(); - let bases = BaseAddresses::default(); - let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); - assert!(result.is_ok()); - let result = result.unwrap(); - assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); - assert!(result.table().is_none()); - } - - #[test] - fn test_eh_frame_hdr_omit_table() { - let section = Section::with_endian(Endian::Little) - .L8(1) - .L8(0x0b) - .L8(0x03) - .L8(0xff) - .L32(0x12345) - .L32(2); - let section = section.get_contents().unwrap(); - let bases = BaseAddresses::default(); - let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); - assert!(result.is_ok()); - let result = result.unwrap(); - assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); - assert!(result.table().is_none()); - } - - #[test] - fn test_eh_frame_hdr_varlen_table() { - let section = Section::with_endian(Endian::Little) - .L8(1) - .L8(0x0b) - .L8(0x03) - .L8(0x01) - .L32(0x12345) - .L32(2); - let section = section.get_contents().unwrap(); - let bases = BaseAddresses::default(); - let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); - assert!(result.is_ok()); - let result = result.unwrap(); - assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); - let table = result.table(); - assert!(table.is_some()); - let table = table.unwrap(); - assert_eq!( - table.lookup(0, &bases), - Err(Error::VariableLengthSearchTable) - ); - } - - #[test] - fn test_eh_frame_hdr_indirect_length() { - let section = Section::with_endian(Endian::Little) - .L8(1) - .L8(0x0b) - .L8(0x83) - .L8(0x0b) - .L32(0x12345) - .L32(2); - let section = section.get_contents().unwrap(); - let bases = BaseAddresses::default(); - let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), Error::UnsupportedPointerEncoding); - } - - #[test] - fn test_eh_frame_hdr_indirect_ptrs() { - let section = Section::with_endian(Endian::Little) - .L8(1) - .L8(0x8b) - .L8(0x03) - .L8(0x8b) - .L32(0x12345) - .L32(2) - .L32(10) - .L32(1) - .L32(20) - .L32(2); - let section = section.get_contents().unwrap(); - let bases = BaseAddresses::default(); - let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); - assert!(result.is_ok()); - let result = result.unwrap(); - assert_eq!(result.eh_frame_ptr(), Pointer::Indirect(0x12345)); - let table = result.table(); - assert!(table.is_some()); - let table = table.unwrap(); - assert_eq!( - table.lookup(0, &bases), - Err(Error::UnsupportedPointerEncoding) - ); - } - - #[test] - fn test_eh_frame_hdr_good() { - let section = Section::with_endian(Endian::Little) - .L8(1) - .L8(0x0b) - .L8(0x03) - .L8(0x0b) - .L32(0x12345) - .L32(2) - .L32(10) - .L32(1) - .L32(20) - .L32(2); - let section = section.get_contents().unwrap(); - let bases = BaseAddresses::default(); - let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); - assert!(result.is_ok()); - let result = result.unwrap(); - assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); - let table = result.table(); - assert!(table.is_some()); - let table = table.unwrap(); - assert_eq!(table.lookup(0, &bases), Ok(Pointer::Direct(1))); - assert_eq!(table.lookup(9, &bases), Ok(Pointer::Direct(1))); - assert_eq!(table.lookup(10, &bases), Ok(Pointer::Direct(1))); - assert_eq!(table.lookup(11, &bases), Ok(Pointer::Direct(1))); - assert_eq!(table.lookup(19, &bases), Ok(Pointer::Direct(1))); - assert_eq!(table.lookup(20, &bases), Ok(Pointer::Direct(2))); - assert_eq!(table.lookup(21, &bases), Ok(Pointer::Direct(2))); - assert_eq!(table.lookup(100_000, &bases), Ok(Pointer::Direct(2))); - } - - #[test] - fn test_eh_frame_fde_for_address_good() { - // First, setup eh_frame - // Write the CIE first so that its length gets set before we clone it - // into the FDE. - let mut cie = make_test_cie(); - cie.format = Format::Dwarf32; - cie.version = 1; - - let start_of_cie = Label::new(); - let end_of_cie = Label::new(); - - let kind = eh_frame_le(); - let section = Section::with_endian(kind.endian()) - .append_repeated(0, 16) - .mark(&start_of_cie) - .cie(kind, None, &mut cie) - .mark(&end_of_cie); - - let mut fde1 = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 9, - address_range: 4, - augmentation: None, - instructions: EndianSlice::new(&[], LittleEndian), - }; - let mut fde2 = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 20, - address_range: 8, - augmentation: None, - instructions: EndianSlice::new(&[], LittleEndian), - }; - - let start_of_fde1 = Label::new(); - let start_of_fde2 = Label::new(); - - let section = section - // +4 for the FDE length before the CIE offset. - .mark(&start_of_fde1) - .fde(kind, (&start_of_fde1 - &start_of_cie + 4) as u64, &mut fde1) - .mark(&start_of_fde2) - .fde(kind, (&start_of_fde2 - &start_of_cie + 4) as u64, &mut fde2); - - section.start().set_const(0); - let section = section.get_contents().unwrap(); - let eh_frame = kind.section(§ion); - - // Setup eh_frame_hdr - let section = Section::with_endian(kind.endian()) - .L8(1) - .L8(0x0b) - .L8(0x03) - .L8(0x0b) - .L32(0x12345) - .L32(2) - .L32(10) - .L32(0x12345 + start_of_fde1.value().unwrap() as u32) - .L32(20) - .L32(0x12345 + start_of_fde2.value().unwrap() as u32); - - let section = section.get_contents().unwrap(); - let bases = BaseAddresses::default(); - let eh_frame_hdr = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); - assert!(eh_frame_hdr.is_ok()); - let eh_frame_hdr = eh_frame_hdr.unwrap(); - - let table = eh_frame_hdr.table(); - assert!(table.is_some()); - let table = table.unwrap(); - - let bases = Default::default(); - let mut iter = table.iter(&bases); - assert_eq!( - iter.next(), - Ok(Some(( - Pointer::Direct(10), - Pointer::Direct(0x12345 + start_of_fde1.value().unwrap() as u64) - ))) - ); - assert_eq!( - iter.next(), - Ok(Some(( - Pointer::Direct(20), - Pointer::Direct(0x12345 + start_of_fde2.value().unwrap() as u64) - ))) - ); - assert_eq!(iter.next(), Ok(None)); - - assert_eq!( - table.iter(&bases).nth(0), - Ok(Some(( - Pointer::Direct(10), - Pointer::Direct(0x12345 + start_of_fde1.value().unwrap() as u64) - ))) - ); - - assert_eq!( - table.iter(&bases).nth(1), - Ok(Some(( - Pointer::Direct(20), - Pointer::Direct(0x12345 + start_of_fde2.value().unwrap() as u64) - ))) - ); - assert_eq!(table.iter(&bases).nth(2), Ok(None)); - - let f = |_: &_, _: &_, o: EhFrameOffset| { - assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize)); - Ok(cie.clone()) - }; - assert_eq!( - table.fde_for_address(&eh_frame, &bases, 9, f), - Ok(fde1.clone()) - ); - assert_eq!( - table.fde_for_address(&eh_frame, &bases, 10, f), - Ok(fde1.clone()) - ); - assert_eq!(table.fde_for_address(&eh_frame, &bases, 11, f), Ok(fde1)); - assert_eq!( - table.fde_for_address(&eh_frame, &bases, 19, f), - Err(Error::NoUnwindInfoForAddress) - ); - assert_eq!( - table.fde_for_address(&eh_frame, &bases, 20, f), - Ok(fde2.clone()) - ); - assert_eq!(table.fde_for_address(&eh_frame, &bases, 21, f), Ok(fde2)); - assert_eq!( - table.fde_for_address(&eh_frame, &bases, 100_000, f), - Err(Error::NoUnwindInfoForAddress) - ); - } - - #[test] - fn test_eh_frame_stops_at_zero_length() { - let section = Section::with_endian(Endian::Little).L32(0); - let section = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(§ion, LittleEndian); - let bases = Default::default(); - - assert_eq!( - parse_cfi_entry(&bases, &EhFrame::new(&*section, LittleEndian), rest), - Ok(None) - ); - - assert_eq!( - EhFrame::new(§ion, LittleEndian).cie_from_offset(&bases, EhFrameOffset(0)), - Err(Error::NoEntryAtGivenOffset) - ); - } - - fn resolve_cie_offset(buf: &[u8], cie_offset: usize) -> Result<usize> { - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf64, - cie: make_test_cie(), - initial_segment: 0, - initial_address: 0xfeed_beef, - address_range: 39, - augmentation: None, - instructions: EndianSlice::new(&[], LittleEndian), - }; - - let kind = eh_frame_le(); - let section = Section::with_endian(kind.endian()) - .append_bytes(&buf) - .fde(kind, cie_offset as u64, &mut fde) - .append_bytes(&buf); - - let section = section.get_contents().unwrap(); - let eh_frame = kind.section(§ion); - let input = &mut EndianSlice::new(§ion[buf.len()..], LittleEndian); - - let bases = Default::default(); - match parse_cfi_entry(&bases, &eh_frame, input) { - Ok(Some(CieOrFde::Fde(partial))) => Ok(partial.cie_offset.0), - Err(e) => Err(e), - otherwise => panic!("Unexpected result: {:#?}", otherwise), - } - } - - #[test] - fn test_eh_frame_resolve_cie_offset_ok() { - let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let cie_offset = 2; - // + 4 for size of length field - assert_eq!( - resolve_cie_offset(&buf, buf.len() + 4 - cie_offset), - Ok(cie_offset) - ); - } - - #[test] - fn test_eh_frame_resolve_cie_offset_out_of_bounds() { - let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - assert_eq!( - resolve_cie_offset(&buf, buf.len() + 4 + 2), - Err(Error::OffsetOutOfBounds) - ); - } - - #[test] - fn test_eh_frame_resolve_cie_offset_underflow() { - let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - assert_eq!( - resolve_cie_offset(&buf, ::core::usize::MAX), - Err(Error::OffsetOutOfBounds) - ); - } - - #[test] - fn test_eh_frame_fde_ok() { - let mut cie = make_test_cie(); - cie.format = Format::Dwarf32; - cie.version = 1; - - let start_of_cie = Label::new(); - let end_of_cie = Label::new(); - - // Write the CIE first so that its length gets set before we clone it - // into the FDE. - let kind = eh_frame_le(); - let section = Section::with_endian(kind.endian()) - .append_repeated(0, 16) - .mark(&start_of_cie) - .cie(kind, None, &mut cie) - .mark(&end_of_cie); - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_beef, - address_range: 999, - augmentation: None, - instructions: EndianSlice::new(&[], LittleEndian), - }; - - let section = section - // +4 for the FDE length before the CIE offset. - .fde(kind, (&end_of_cie - &start_of_cie + 4) as u64, &mut fde); - - section.start().set_const(0); - let section = section.get_contents().unwrap(); - let eh_frame = kind.section(§ion); - let section = EndianSlice::new(§ion, LittleEndian); - - let mut offset = None; - match parse_fde( - eh_frame, - &mut section.range_from(end_of_cie.value().unwrap() as usize..), - |_, _, o| { - offset = Some(o); - assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize)); - Ok(cie.clone()) - }, - ) { - Ok(actual) => assert_eq!(actual, fde), - otherwise => panic!("Unexpected result {:?}", otherwise), - } - assert!(offset.is_some()); - } - - #[test] - fn test_eh_frame_fde_out_of_bounds() { - let mut cie = make_test_cie(); - cie.version = 1; - - let end_of_cie = Label::new(); - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf64, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_beef, - address_range: 999, - augmentation: None, - instructions: EndianSlice::new(&[], LittleEndian), - }; - - let kind = eh_frame_le(); - let section = Section::with_endian(kind.endian()) - .cie(kind, None, &mut cie) - .mark(&end_of_cie) - .fde(kind, 99_999_999_999_999, &mut fde); - - section.start().set_const(0); - let section = section.get_contents().unwrap(); - let eh_frame = kind.section(§ion); - let section = EndianSlice::new(§ion, LittleEndian); - - let result = parse_fde( - eh_frame, - &mut section.range_from(end_of_cie.value().unwrap() as usize..), - UnwindSection::cie_from_offset, - ); - assert_eq!(result, Err(Error::OffsetOutOfBounds)); - } - - #[test] - fn test_augmentation_parse_not_z_augmentation() { - let augmentation = &mut EndianSlice::new(b"wtf", NativeEndian); - let bases = Default::default(); - let address_size = 8; - let section = EhFrame::new(&[], NativeEndian); - let input = &mut EndianSlice::new(&[], NativeEndian); - assert_eq!( - Augmentation::parse(augmentation, &bases, address_size, §ion, input), - Err(Error::UnknownAugmentation) - ); - } - - #[test] - fn test_augmentation_parse_just_signal_trampoline() { - let aug_str = &mut EndianSlice::new(b"S", LittleEndian); - let bases = Default::default(); - let address_size = 8; - let section = EhFrame::new(&[], LittleEndian); - let input = &mut EndianSlice::new(&[], LittleEndian); - - let mut augmentation = Augmentation::default(); - augmentation.is_signal_trampoline = true; - - assert_eq!( - Augmentation::parse(aug_str, &bases, address_size, §ion, input), - Ok(augmentation) - ); - } - - #[test] - fn test_augmentation_parse_unknown_part_of_z_augmentation() { - // The 'Z' character is not defined by the z-style augmentation. - let bases = Default::default(); - let address_size = 8; - let section = Section::with_endian(Endian::Little) - .uleb(4) - .append_repeated(4, 4) - .get_contents() - .unwrap(); - let section = EhFrame::new(§ion, LittleEndian); - let input = &mut section.section().clone(); - let augmentation = &mut EndianSlice::new(b"zZ", LittleEndian); - assert_eq!( - Augmentation::parse(augmentation, &bases, address_size, §ion, input), - Err(Error::UnknownAugmentation) - ); - } - - #[test] - #[allow(non_snake_case)] - fn test_augmentation_parse_L() { - let bases = Default::default(); - let address_size = 8; - let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; - - let section = Section::with_endian(Endian::Little) - .uleb(1) - .D8(constants::DW_EH_PE_uleb128.0) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = EhFrame::new(§ion, LittleEndian); - let input = &mut section.section().clone(); - let aug_str = &mut EndianSlice::new(b"zL", LittleEndian); - - let mut augmentation = Augmentation::default(); - augmentation.lsda = Some(constants::DW_EH_PE_uleb128); - - assert_eq!( - Augmentation::parse(aug_str, &bases, address_size, §ion, input), - Ok(augmentation) - ); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - #[allow(non_snake_case)] - fn test_augmentation_parse_P() { - let bases = Default::default(); - let address_size = 8; - let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; - - let section = Section::with_endian(Endian::Little) - .uleb(9) - .D8(constants::DW_EH_PE_udata8.0) - .L64(0xf00d_f00d) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = EhFrame::new(§ion, LittleEndian); - let input = &mut section.section().clone(); - let aug_str = &mut EndianSlice::new(b"zP", LittleEndian); - - let mut augmentation = Augmentation::default(); - augmentation.personality = Some((constants::DW_EH_PE_udata8, Pointer::Direct(0xf00d_f00d))); - - assert_eq!( - Augmentation::parse(aug_str, &bases, address_size, §ion, input), - Ok(augmentation) - ); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - #[allow(non_snake_case)] - fn test_augmentation_parse_R() { - let bases = Default::default(); - let address_size = 8; - let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; - - let section = Section::with_endian(Endian::Little) - .uleb(1) - .D8(constants::DW_EH_PE_udata4.0) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = EhFrame::new(§ion, LittleEndian); - let input = &mut section.section().clone(); - let aug_str = &mut EndianSlice::new(b"zR", LittleEndian); - - let mut augmentation = Augmentation::default(); - augmentation.fde_address_encoding = Some(constants::DW_EH_PE_udata4); - - assert_eq!( - Augmentation::parse(aug_str, &bases, address_size, §ion, input), - Ok(augmentation) - ); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - #[allow(non_snake_case)] - fn test_augmentation_parse_S() { - let bases = Default::default(); - let address_size = 8; - let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; - - let section = Section::with_endian(Endian::Little) - .uleb(0) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = EhFrame::new(§ion, LittleEndian); - let input = &mut section.section().clone(); - let aug_str = &mut EndianSlice::new(b"zS", LittleEndian); - - let mut augmentation = Augmentation::default(); - augmentation.is_signal_trampoline = true; - - assert_eq!( - Augmentation::parse(aug_str, &bases, address_size, §ion, input), - Ok(augmentation) - ); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - fn test_augmentation_parse_all() { - let bases = Default::default(); - let address_size = 8; - let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; - - let section = Section::with_endian(Endian::Little) - .uleb(1 + 9 + 1) - // L - .D8(constants::DW_EH_PE_uleb128.0) - // P - .D8(constants::DW_EH_PE_udata8.0) - .L64(0x1bad_f00d) - // R - .D8(constants::DW_EH_PE_uleb128.0) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = EhFrame::new(§ion, LittleEndian); - let input = &mut section.section().clone(); - let aug_str = &mut EndianSlice::new(b"zLPRS", LittleEndian); - - let augmentation = Augmentation { - lsda: Some(constants::DW_EH_PE_uleb128), - personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0x1bad_f00d))), - fde_address_encoding: Some(constants::DW_EH_PE_uleb128), - is_signal_trampoline: true, - }; - - assert_eq!( - Augmentation::parse(aug_str, &bases, address_size, §ion, input), - Ok(augmentation) - ); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - fn test_eh_frame_fde_no_augmentation() { - let instrs = [1, 2, 3, 4]; - let cie_offset = 1; - - let mut cie = make_test_cie(); - cie.format = Format::Dwarf32; - cie.version = 1; - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_face, - address_range: 9000, - augmentation: None, - instructions: EndianSlice::new(&instrs, LittleEndian), - }; - - let rest = [1, 2, 3, 4]; - - let kind = eh_frame_le(); - let section = Section::with_endian(kind.endian()) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = kind.section(§ion); - let input = &mut section.section().clone(); - - let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); - assert_eq!(result, Ok(fde)); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - fn test_eh_frame_fde_empty_augmentation() { - let instrs = [1, 2, 3, 4]; - let cie_offset = 1; - - let mut cie = make_test_cie(); - cie.format = Format::Dwarf32; - cie.version = 1; - cie.augmentation = Some(Augmentation::default()); - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_face, - address_range: 9000, - augmentation: Some(AugmentationData::default()), - instructions: EndianSlice::new(&instrs, LittleEndian), - }; - - let rest = [1, 2, 3, 4]; - - let kind = eh_frame_le(); - let section = Section::with_endian(kind.endian()) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = kind.section(§ion); - let input = &mut section.section().clone(); - - let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); - assert_eq!(result, Ok(fde)); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - fn test_eh_frame_fde_lsda_augmentation() { - let instrs = [1, 2, 3, 4]; - let cie_offset = 1; - - let mut cie = make_test_cie(); - cie.format = Format::Dwarf32; - cie.version = 1; - cie.augmentation = Some(Augmentation::default()); - cie.augmentation.as_mut().unwrap().lsda = Some(constants::DW_EH_PE_absptr); - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_face, - address_range: 9000, - augmentation: Some(AugmentationData { - lsda: Some(Pointer::Direct(0x1122_3344)), - }), - instructions: EndianSlice::new(&instrs, LittleEndian), - }; - - let rest = [1, 2, 3, 4]; - - let kind = eh_frame_le(); - let section = Section::with_endian(kind.endian()) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = kind.section(§ion); - let input = &mut section.section().clone(); - - let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); - assert_eq!(result, Ok(fde)); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - fn test_eh_frame_fde_lsda_function_relative() { - let instrs = [1, 2, 3, 4]; - let cie_offset = 1; - - let mut cie = make_test_cie(); - cie.format = Format::Dwarf32; - cie.version = 1; - cie.augmentation = Some(Augmentation::default()); - cie.augmentation.as_mut().unwrap().lsda = Some(constants::DwEhPe( - constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_absptr.0, - )); - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0, - initial_address: 0xfeed_face, - address_range: 9000, - augmentation: Some(AugmentationData { - lsda: Some(Pointer::Direct(0xbeef)), - }), - instructions: EndianSlice::new(&instrs, LittleEndian), - }; - - let rest = [1, 2, 3, 4]; - - let kind = eh_frame_le(); - let section = Section::with_endian(kind.endian()) - .append_repeated(10, 10) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&rest) - .get_contents() - .unwrap(); - let section = kind.section(§ion); - let input = &mut section.section().range_from(10..); - - // Adjust the FDE's augmentation to be relative to the function. - fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(0xfeed_face + 0xbeef)); - - let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); - assert_eq!(result, Ok(fde)); - assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); - } - - #[test] - fn test_eh_frame_cie_personality_function_relative_bad_context() { - let instrs = [1, 2, 3, 4]; - - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let aug_len = Label::new(); - let aug_start = Label::new(); - let aug_end = Label::new(); - - let section = Section::with_endian(Endian::Little) - // Length - .L32(&length) - .mark(&start) - // CIE ID - .L32(0) - // Version - .D8(1) - // Augmentation - .append_bytes(b"zP\0") - // Code alignment factor - .uleb(1) - // Data alignment factor - .sleb(1) - // Return address register - .uleb(1) - // Augmentation data length. This is a uleb, be we rely on the value - // being less than 2^7 and therefore a valid uleb (can't use Label - // with uleb). - .D8(&aug_len) - .mark(&aug_start) - // Augmentation data. Personality encoding and then encoded pointer. - .D8(constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_uleb128.0) - .uleb(1) - .mark(&aug_end) - // Initial instructions - .append_bytes(&instrs) - .mark(&end); - - length.set_const((&end - &start) as u64); - aug_len.set_const((&aug_end - &aug_start) as u64); - - let section = section.get_contents().unwrap(); - let section = EhFrame::new(§ion, LittleEndian); - - let bases = BaseAddresses::default(); - let mut iter = section.entries(&bases); - assert_eq!(iter.next(), Err(Error::FuncRelativePointerInBadContext)); - } - - #[test] - fn register_rule_map_eq() { - // Different order, but still equal. - let map1: RegisterRuleMap<EndianSlice<LittleEndian>> = [ - (Register(0), RegisterRule::SameValue), - (Register(3), RegisterRule::Offset(1)), - ] - .iter() - .collect(); - let map2: RegisterRuleMap<EndianSlice<LittleEndian>> = [ - (Register(3), RegisterRule::Offset(1)), - (Register(0), RegisterRule::SameValue), - ] - .iter() - .collect(); - assert_eq!(map1, map2); - assert_eq!(map2, map1); - - // Not equal. - let map3: RegisterRuleMap<EndianSlice<LittleEndian>> = [ - (Register(0), RegisterRule::SameValue), - (Register(2), RegisterRule::Offset(1)), - ] - .iter() - .collect(); - let map4: RegisterRuleMap<EndianSlice<LittleEndian>> = [ - (Register(3), RegisterRule::Offset(1)), - (Register(0), RegisterRule::SameValue), - ] - .iter() - .collect(); - assert!(map3 != map4); - assert!(map4 != map3); - - // One has undefined explicitly set, other implicitly has undefined. - let mut map5 = RegisterRuleMap::<EndianSlice<LittleEndian>>::default(); - map5.set(Register(0), RegisterRule::SameValue).unwrap(); - map5.set(Register(0), RegisterRule::Undefined).unwrap(); - let map6 = RegisterRuleMap::<EndianSlice<LittleEndian>>::default(); - assert_eq!(map5, map6); - assert_eq!(map6, map5); - } - - #[test] - fn iter_register_rules() { - let mut row = UnwindTableRow::<EndianSlice<LittleEndian>>::default(); - row.registers = [ - (Register(0), RegisterRule::SameValue), - (Register(1), RegisterRule::Offset(1)), - (Register(2), RegisterRule::ValOffset(2)), - ] - .iter() - .collect(); - - let mut found0 = false; - let mut found1 = false; - let mut found2 = false; - - for &(register, ref rule) in row.registers() { - match register.0 { - 0 => { - assert_eq!(found0, false); - found0 = true; - assert_eq!(*rule, RegisterRule::SameValue); - } - 1 => { - assert_eq!(found1, false); - found1 = true; - assert_eq!(*rule, RegisterRule::Offset(1)); - } - 2 => { - assert_eq!(found2, false); - found2 = true; - assert_eq!(*rule, RegisterRule::ValOffset(2)); - } - x => panic!("Unexpected register rule: ({}, {:?})", x, rule), - } - } - - assert_eq!(found0, true); - assert_eq!(found1, true); - assert_eq!(found2, true); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn size_of_unwind_ctx() { - use core::mem; - let size = mem::size_of::<UnwindContext<EndianSlice<NativeEndian>>>(); - let max_size = 30968; - if size > max_size { - assert_eq!(size, max_size); - } - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn size_of_register_rule_map() { - use core::mem; - let size = mem::size_of::<RegisterRuleMap<EndianSlice<NativeEndian>>>(); - let max_size = 6152; - if size > max_size { - assert_eq!(size, max_size); - } - } - - #[test] - fn test_parse_pointer_encoding_ok() { - use crate::endianity::NativeEndian; - let expected = - constants::DwEhPe(constants::DW_EH_PE_uleb128.0 | constants::DW_EH_PE_pcrel.0); - let input = [expected.0, 1, 2, 3, 4]; - let input = &mut EndianSlice::new(&input, NativeEndian); - assert_eq!(parse_pointer_encoding(input), Ok(expected)); - assert_eq!(*input, EndianSlice::new(&[1, 2, 3, 4], NativeEndian)); - } - - #[test] - fn test_parse_pointer_encoding_bad_encoding() { - use crate::endianity::NativeEndian; - let expected = - constants::DwEhPe((constants::DW_EH_PE_sdata8.0 + 1) | constants::DW_EH_PE_pcrel.0); - let input = [expected.0, 1, 2, 3, 4]; - let input = &mut EndianSlice::new(&input, NativeEndian); - assert_eq!( - Err(Error::UnknownPointerEncoding), - parse_pointer_encoding(input) - ); - } - - #[test] - fn test_parse_encoded_pointer_absptr() { - let encoding = constants::DW_EH_PE_absptr; - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .L32(0xf00d_f00d) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0xf00d_f00d)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_pcrel() { - let encoding = constants::DW_EH_PE_pcrel; - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .append_repeated(0, 0x10) - .L32(0x1) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input.range_from(0x10..); - - let parameters = PointerEncodingParameters { - bases: &BaseAddresses::default().set_eh_frame(0x100).eh_frame, - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x111)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_pcrel_undefined() { - let encoding = constants::DW_EH_PE_pcrel; - - let input = Section::with_endian(Endian::Little).L32(0x1); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Err(Error::PcRelativePointerButSectionBaseIsUndefined) - ); - } - - #[test] - fn test_parse_encoded_pointer_textrel() { - let encoding = constants::DW_EH_PE_textrel; - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .L32(0x1) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &BaseAddresses::default().set_text(0x10).eh_frame, - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x11)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_textrel_undefined() { - let encoding = constants::DW_EH_PE_textrel; - - let input = Section::with_endian(Endian::Little).L32(0x1); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Err(Error::TextRelativePointerButTextBaseIsUndefined) - ); - } - - #[test] - fn test_parse_encoded_pointer_datarel() { - let encoding = constants::DW_EH_PE_datarel; - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .L32(0x1) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &BaseAddresses::default().set_got(0x10).eh_frame, - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x11)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_datarel_undefined() { - let encoding = constants::DW_EH_PE_datarel; - - let input = Section::with_endian(Endian::Little).L32(0x1); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Err(Error::DataRelativePointerButDataBaseIsUndefined) - ); - } - - #[test] - fn test_parse_encoded_pointer_funcrel() { - let encoding = constants::DW_EH_PE_funcrel; - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .L32(0x1) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: Some(0x10), - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x11)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_funcrel_undefined() { - let encoding = constants::DW_EH_PE_funcrel; - - let input = Section::with_endian(Endian::Little).L32(0x1); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Err(Error::FuncRelativePointerInBadContext) - ); - } - - #[test] - fn test_parse_encoded_pointer_uleb128() { - let encoding = - constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_uleb128.0); - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .uleb(0x12_3456) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x12_3456)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_udata2() { - let encoding = - constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata2.0); - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .L16(0x1234) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x1234)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_udata4() { - let encoding = - constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata4.0); - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .L32(0x1234_5678) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x1234_5678)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_udata8() { - let encoding = - constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata8.0); - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .L64(0x1234_5678_1234_5678) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x1234_5678_1234_5678)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_sleb128() { - let encoding = - constants::DwEhPe(constants::DW_EH_PE_textrel.0 | constants::DW_EH_PE_sleb128.0); - let expected_rest = [1, 2, 3, 4]; - - let input = Section::with_endian(Endian::Little) - .sleb(-0x1111) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &BaseAddresses::default().set_text(0x1111_1111).eh_frame, - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(0x1111_0000)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_sdata2() { - let encoding = - constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata2.0); - let expected_rest = [1, 2, 3, 4]; - let expected = 0x111 as i16; - - let input = Section::with_endian(Endian::Little) - .L16(expected as u16) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(expected as u64)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_sdata4() { - let encoding = - constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata4.0); - let expected_rest = [1, 2, 3, 4]; - let expected = 0x111_1111 as i32; - - let input = Section::with_endian(Endian::Little) - .L32(expected as u32) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(expected as u64)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_sdata8() { - let encoding = - constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata8.0); - let expected_rest = [1, 2, 3, 4]; - let expected = -0x11_1111_1222_2222 as i64; - - let input = Section::with_endian(Endian::Little) - .L64(expected as u64) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Direct(expected as u64)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_encoded_pointer_omit() { - let encoding = constants::DW_EH_PE_omit; - - let input = Section::with_endian(Endian::Little).L32(0x1); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Err(Error::CannotParseOmitPointerEncoding) - ); - assert_eq!(rest, input); - } - - #[test] - fn test_parse_encoded_pointer_bad_encoding() { - let encoding = constants::DwEhPe(constants::DW_EH_PE_sdata8.0 + 1); - - let input = Section::with_endian(Endian::Little).L32(0x1); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Err(Error::UnknownPointerEncoding) - ); - } - - #[test] - fn test_parse_encoded_pointer_aligned() { - // FIXME: support this encoding! - - let encoding = constants::DW_EH_PE_aligned; - - let input = Section::with_endian(Endian::Little).L32(0x1); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Err(Error::UnsupportedPointerEncoding) - ); - } - - #[test] - fn test_parse_encoded_pointer_indirect() { - let expected_rest = [1, 2, 3, 4]; - let encoding = constants::DW_EH_PE_indirect; - - let input = Section::with_endian(Endian::Little) - .L32(0x1234_5678) - .append_bytes(&expected_rest); - let input = input.get_contents().unwrap(); - let input = EndianSlice::new(&input, LittleEndian); - let mut rest = input; - - let parameters = PointerEncodingParameters { - bases: &SectionBaseAddresses::default(), - func_base: None, - address_size: 4, - section: &input, - }; - assert_eq!( - parse_encoded_pointer(encoding, ¶meters, &mut rest), - Ok(Pointer::Indirect(0x1234_5678)) - ); - assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); - } -} diff --git a/vendor/gimli/src/read/dwarf.rs b/vendor/gimli/src/read/dwarf.rs deleted file mode 100644 index 2f8dcb3..0000000 --- a/vendor/gimli/src/read/dwarf.rs +++ /dev/null @@ -1,1210 +0,0 @@ -use alloc::string::String; -use alloc::sync::Arc; - -use crate::common::{ - DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase, - DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, - DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwarfFileType, DwoId, Encoding, - LocationListsOffset, RangeListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset, -}; -use crate::constants; -use crate::read::{ - Abbreviations, AbbreviationsCache, AbbreviationsCacheStrategy, AttributeValue, DebugAbbrev, - DebugAddr, DebugAranges, DebugCuIndex, DebugInfo, DebugInfoUnitHeadersIter, DebugLine, - DebugLineStr, DebugLoc, DebugLocLists, DebugRngLists, DebugStr, DebugStrOffsets, DebugTuIndex, - DebugTypes, DebugTypesUnitHeadersIter, DebuggingInformationEntry, EntriesCursor, EntriesRaw, - EntriesTree, Error, IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, - RawLocListIter, RawRngListIter, Reader, ReaderOffset, ReaderOffsetId, Result, RngListIter, - Section, UnitHeader, UnitIndex, UnitIndexSectionIterator, UnitOffset, UnitType, -}; - -/// All of the commonly used DWARF sections, and other common information. -#[derive(Debug, Default)] -pub struct Dwarf<R> { - /// The `.debug_abbrev` section. - pub debug_abbrev: DebugAbbrev<R>, - - /// The `.debug_addr` section. - pub debug_addr: DebugAddr<R>, - - /// The `.debug_aranges` section. - pub debug_aranges: DebugAranges<R>, - - /// The `.debug_info` section. - pub debug_info: DebugInfo<R>, - - /// The `.debug_line` section. - pub debug_line: DebugLine<R>, - - /// The `.debug_line_str` section. - pub debug_line_str: DebugLineStr<R>, - - /// The `.debug_str` section. - pub debug_str: DebugStr<R>, - - /// The `.debug_str_offsets` section. - pub debug_str_offsets: DebugStrOffsets<R>, - - /// The `.debug_types` section. - pub debug_types: DebugTypes<R>, - - /// The location lists in the `.debug_loc` and `.debug_loclists` sections. - pub locations: LocationLists<R>, - - /// The range lists in the `.debug_ranges` and `.debug_rnglists` sections. - pub ranges: RangeLists<R>, - - /// The type of this file. - pub file_type: DwarfFileType, - - /// The DWARF sections for a supplementary object file. - pub sup: Option<Arc<Dwarf<R>>>, - - /// A cache of previously parsed abbreviations for units in this file. - pub abbreviations_cache: AbbreviationsCache, -} - -impl<T> Dwarf<T> { - /// Try to load the DWARF sections using the given loader function. - /// - /// `section` loads a DWARF section from the object file. - /// It should return an empty section if the section does not exist. - /// - /// `section` may either directly return a `Reader` instance (such as - /// `EndianSlice`), or it may return some other type and then convert - /// that type into a `Reader` using `Dwarf::borrow`. - /// - /// After loading, the user should set the `file_type` field and - /// call `load_sup` if required. - pub fn load<F, E>(mut section: F) -> core::result::Result<Self, E> - where - F: FnMut(SectionId) -> core::result::Result<T, E>, - { - // Section types are inferred. - let debug_loc = Section::load(&mut section)?; - let debug_loclists = Section::load(&mut section)?; - let debug_ranges = Section::load(&mut section)?; - let debug_rnglists = Section::load(&mut section)?; - Ok(Dwarf { - debug_abbrev: Section::load(&mut section)?, - debug_addr: Section::load(&mut section)?, - debug_aranges: Section::load(&mut section)?, - debug_info: Section::load(&mut section)?, - debug_line: Section::load(&mut section)?, - debug_line_str: Section::load(&mut section)?, - debug_str: Section::load(&mut section)?, - debug_str_offsets: Section::load(&mut section)?, - debug_types: Section::load(&mut section)?, - locations: LocationLists::new(debug_loc, debug_loclists), - ranges: RangeLists::new(debug_ranges, debug_rnglists), - file_type: DwarfFileType::Main, - sup: None, - abbreviations_cache: AbbreviationsCache::new(), - }) - } - - /// Load the DWARF sections from the supplementary object file. - /// - /// `section` operates the same as for `load`. - /// - /// Sets `self.sup`, replacing any previous value. - pub fn load_sup<F, E>(&mut self, section: F) -> core::result::Result<(), E> - where - F: FnMut(SectionId) -> core::result::Result<T, E>, - { - self.sup = Some(Arc::new(Self::load(section)?)); - Ok(()) - } - - /// Create a `Dwarf` structure that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// It can be useful to load DWARF sections into owned data structures, - /// such as `Vec`. However, we do not implement the `Reader` trait - /// for `Vec`, because it would be very inefficient, but this trait - /// is required for all of the methods that parse the DWARF data. - /// So we first load the DWARF sections into `Vec`s, and then use - /// `borrow` to create `Reader`s that reference the data. - /// - /// ```rust,no_run - /// # fn example() -> Result<(), gimli::Error> { - /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; - /// # let sup_loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; - /// // Read the DWARF sections into `Vec`s with whatever object loader you're using. - /// let mut owned_dwarf: gimli::Dwarf<Vec<u8>> = gimli::Dwarf::load(loader)?; - /// owned_dwarf.load_sup(sup_loader)?; - /// // Create references to the DWARF sections. - /// let dwarf = owned_dwarf.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// # unreachable!() - /// # } - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf<R> - where - F: FnMut(&'a T) -> R, - { - Dwarf { - debug_abbrev: self.debug_abbrev.borrow(&mut borrow), - debug_addr: self.debug_addr.borrow(&mut borrow), - debug_aranges: self.debug_aranges.borrow(&mut borrow), - debug_info: self.debug_info.borrow(&mut borrow), - debug_line: self.debug_line.borrow(&mut borrow), - debug_line_str: self.debug_line_str.borrow(&mut borrow), - debug_str: self.debug_str.borrow(&mut borrow), - debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow), - debug_types: self.debug_types.borrow(&mut borrow), - locations: self.locations.borrow(&mut borrow), - ranges: self.ranges.borrow(&mut borrow), - file_type: self.file_type, - sup: self.sup().map(|sup| Arc::new(sup.borrow(borrow))), - abbreviations_cache: AbbreviationsCache::new(), - } - } - - /// Return a reference to the DWARF sections for supplementary object file. - pub fn sup(&self) -> Option<&Dwarf<T>> { - self.sup.as_ref().map(Arc::as_ref) - } -} - -impl<R: Reader> Dwarf<R> { - /// Parse abbreviations and store them in the cache. - /// - /// This will iterate over the units in `self.debug_info` to determine the - /// abbreviations offsets. - /// - /// Errors during parsing abbreviations are also stored in the cache. - /// Errors during iterating over the units are ignored. - pub fn populate_abbreviations_cache(&mut self, strategy: AbbreviationsCacheStrategy) { - self.abbreviations_cache - .populate(strategy, &self.debug_abbrev, self.debug_info.units()); - } - - /// Iterate the unit headers in the `.debug_info` section. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - #[inline] - pub fn units(&self) -> DebugInfoUnitHeadersIter<R> { - self.debug_info.units() - } - - /// Construct a new `Unit` from the given unit header. - #[inline] - pub fn unit(&self, header: UnitHeader<R>) -> Result<Unit<R>> { - Unit::new(self, header) - } - - /// Iterate the type-unit headers in the `.debug_types` section. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - #[inline] - pub fn type_units(&self) -> DebugTypesUnitHeadersIter<R> { - self.debug_types.units() - } - - /// Parse the abbreviations for a compilation unit. - #[inline] - pub fn abbreviations(&self, unit: &UnitHeader<R>) -> Result<Arc<Abbreviations>> { - self.abbreviations_cache - .get(&self.debug_abbrev, unit.debug_abbrev_offset()) - } - - /// Return the string offset at the given index. - #[inline] - pub fn string_offset( - &self, - unit: &Unit<R>, - index: DebugStrOffsetsIndex<R::Offset>, - ) -> Result<DebugStrOffset<R::Offset>> { - self.debug_str_offsets - .get_str_offset(unit.header.format(), unit.str_offsets_base, index) - } - - /// Return the string at the given offset in `.debug_str`. - #[inline] - pub fn string(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> { - self.debug_str.get_str(offset) - } - - /// Return the string at the given offset in `.debug_line_str`. - #[inline] - pub fn line_string(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> { - self.debug_line_str.get_str(offset) - } - - /// Return an attribute value as a string slice. - /// - /// If the attribute value is one of: - /// - /// - an inline `DW_FORM_string` string - /// - a `DW_FORM_strp` reference to an offset into the `.debug_str` section - /// - a `DW_FORM_strp_sup` reference to an offset into a supplementary - /// object file - /// - a `DW_FORM_line_strp` reference to an offset into the `.debug_line_str` - /// section - /// - a `DW_FORM_strx` index into the `.debug_str_offsets` entries for the unit - /// - /// then return the attribute's string value. Returns an error if the attribute - /// value does not have a string form, or if a string form has an invalid value. - pub fn attr_string(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<R> { - match attr { - AttributeValue::String(string) => Ok(string), - AttributeValue::DebugStrRef(offset) => self.debug_str.get_str(offset), - AttributeValue::DebugStrRefSup(offset) => { - if let Some(sup) = self.sup() { - sup.debug_str.get_str(offset) - } else { - Err(Error::ExpectedStringAttributeValue) - } - } - AttributeValue::DebugLineStrRef(offset) => self.debug_line_str.get_str(offset), - AttributeValue::DebugStrOffsetsIndex(index) => { - let offset = self.debug_str_offsets.get_str_offset( - unit.header.format(), - unit.str_offsets_base, - index, - )?; - self.debug_str.get_str(offset) - } - _ => Err(Error::ExpectedStringAttributeValue), - } - } - - /// Return the address at the given index. - pub fn address(&self, unit: &Unit<R>, index: DebugAddrIndex<R::Offset>) -> Result<u64> { - self.debug_addr - .get_address(unit.encoding().address_size, unit.addr_base, index) - } - - /// Try to return an attribute value as an address. - /// - /// If the attribute value is one of: - /// - /// - a `DW_FORM_addr` - /// - a `DW_FORM_addrx` index into the `.debug_addr` entries for the unit - /// - /// then return the address. - /// Returns `None` for other forms. - pub fn attr_address(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<Option<u64>> { - match attr { - AttributeValue::Addr(addr) => Ok(Some(addr)), - AttributeValue::DebugAddrIndex(index) => self.address(unit, index).map(Some), - _ => Ok(None), - } - } - - /// Return the range list offset for the given raw offset. - /// - /// This handles adding `DW_AT_GNU_ranges_base` if required. - pub fn ranges_offset_from_raw( - &self, - unit: &Unit<R>, - offset: RawRangeListsOffset<R::Offset>, - ) -> RangeListsOffset<R::Offset> { - if self.file_type == DwarfFileType::Dwo && unit.header.version() < 5 { - RangeListsOffset(offset.0.wrapping_add(unit.rnglists_base.0)) - } else { - RangeListsOffset(offset.0) - } - } - - /// Return the range list offset at the given index. - pub fn ranges_offset( - &self, - unit: &Unit<R>, - index: DebugRngListsIndex<R::Offset>, - ) -> Result<RangeListsOffset<R::Offset>> { - self.ranges - .get_offset(unit.encoding(), unit.rnglists_base, index) - } - - /// Iterate over the `RangeListEntry`s starting at the given offset. - pub fn ranges( - &self, - unit: &Unit<R>, - offset: RangeListsOffset<R::Offset>, - ) -> Result<RngListIter<R>> { - self.ranges.ranges( - offset, - unit.encoding(), - unit.low_pc, - &self.debug_addr, - unit.addr_base, - ) - } - - /// Iterate over the `RawRngListEntry`ies starting at the given offset. - pub fn raw_ranges( - &self, - unit: &Unit<R>, - offset: RangeListsOffset<R::Offset>, - ) -> Result<RawRngListIter<R>> { - self.ranges.raw_ranges(offset, unit.encoding()) - } - - /// Try to return an attribute value as a range list offset. - /// - /// If the attribute value is one of: - /// - /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections - /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit - /// - /// then return the range list offset of the range list. - /// Returns `None` for other forms. - pub fn attr_ranges_offset( - &self, - unit: &Unit<R>, - attr: AttributeValue<R>, - ) -> Result<Option<RangeListsOffset<R::Offset>>> { - match attr { - AttributeValue::RangeListsRef(offset) => { - Ok(Some(self.ranges_offset_from_raw(unit, offset))) - } - AttributeValue::DebugRngListsIndex(index) => self.ranges_offset(unit, index).map(Some), - _ => Ok(None), - } - } - - /// Try to return an attribute value as a range list entry iterator. - /// - /// If the attribute value is one of: - /// - /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections - /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit - /// - /// then return an iterator over the entries in the range list. - /// Returns `None` for other forms. - pub fn attr_ranges( - &self, - unit: &Unit<R>, - attr: AttributeValue<R>, - ) -> Result<Option<RngListIter<R>>> { - match self.attr_ranges_offset(unit, attr)? { - Some(offset) => Ok(Some(self.ranges(unit, offset)?)), - None => Ok(None), - } - } - - /// Return an iterator for the address ranges of a `DebuggingInformationEntry`. - /// - /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges`. - pub fn die_ranges( - &self, - unit: &Unit<R>, - entry: &DebuggingInformationEntry<R>, - ) -> Result<RangeIter<R>> { - let mut low_pc = None; - let mut high_pc = None; - let mut size = None; - let mut attrs = entry.attrs(); - while let Some(attr) = attrs.next()? { - match attr.name() { - constants::DW_AT_low_pc => { - low_pc = Some( - self.attr_address(unit, attr.value())? - .ok_or(Error::UnsupportedAttributeForm)?, - ); - } - constants::DW_AT_high_pc => match attr.value() { - AttributeValue::Udata(val) => size = Some(val), - attr => { - high_pc = Some( - self.attr_address(unit, attr)? - .ok_or(Error::UnsupportedAttributeForm)?, - ); - } - }, - constants::DW_AT_ranges => { - if let Some(list) = self.attr_ranges(unit, attr.value())? { - return Ok(RangeIter(RangeIterInner::List(list))); - } - } - _ => {} - } - } - let range = low_pc.and_then(|begin| { - let end = size.map(|size| begin + size).or(high_pc); - // TODO: perhaps return an error if `end` is `None` - end.map(|end| Range { begin, end }) - }); - Ok(RangeIter(RangeIterInner::Single(range))) - } - - /// Return an iterator for the address ranges of a `Unit`. - /// - /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges` of the - /// root `DebuggingInformationEntry`. - pub fn unit_ranges(&self, unit: &Unit<R>) -> Result<RangeIter<R>> { - let mut cursor = unit.header.entries(&unit.abbreviations); - cursor.next_dfs()?; - let root = cursor.current().ok_or(Error::MissingUnitDie)?; - self.die_ranges(unit, root) - } - - /// Return the location list offset at the given index. - pub fn locations_offset( - &self, - unit: &Unit<R>, - index: DebugLocListsIndex<R::Offset>, - ) -> Result<LocationListsOffset<R::Offset>> { - self.locations - .get_offset(unit.encoding(), unit.loclists_base, index) - } - - /// Iterate over the `LocationListEntry`s starting at the given offset. - pub fn locations( - &self, - unit: &Unit<R>, - offset: LocationListsOffset<R::Offset>, - ) -> Result<LocListIter<R>> { - match self.file_type { - DwarfFileType::Main => self.locations.locations( - offset, - unit.encoding(), - unit.low_pc, - &self.debug_addr, - unit.addr_base, - ), - DwarfFileType::Dwo => self.locations.locations_dwo( - offset, - unit.encoding(), - unit.low_pc, - &self.debug_addr, - unit.addr_base, - ), - } - } - - /// Iterate over the raw `LocationListEntry`s starting at the given offset. - pub fn raw_locations( - &self, - unit: &Unit<R>, - offset: LocationListsOffset<R::Offset>, - ) -> Result<RawLocListIter<R>> { - match self.file_type { - DwarfFileType::Main => self.locations.raw_locations(offset, unit.encoding()), - DwarfFileType::Dwo => self.locations.raw_locations_dwo(offset, unit.encoding()), - } - } - - /// Try to return an attribute value as a location list offset. - /// - /// If the attribute value is one of: - /// - /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections - /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit - /// - /// then return the location list offset of the location list. - /// Returns `None` for other forms. - pub fn attr_locations_offset( - &self, - unit: &Unit<R>, - attr: AttributeValue<R>, - ) -> Result<Option<LocationListsOffset<R::Offset>>> { - match attr { - AttributeValue::LocationListsRef(offset) => Ok(Some(offset)), - AttributeValue::DebugLocListsIndex(index) => { - self.locations_offset(unit, index).map(Some) - } - _ => Ok(None), - } - } - - /// Try to return an attribute value as a location list entry iterator. - /// - /// If the attribute value is one of: - /// - /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections - /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit - /// - /// then return an iterator over the entries in the location list. - /// Returns `None` for other forms. - pub fn attr_locations( - &self, - unit: &Unit<R>, - attr: AttributeValue<R>, - ) -> Result<Option<LocListIter<R>>> { - match self.attr_locations_offset(unit, attr)? { - Some(offset) => Ok(Some(self.locations(unit, offset)?)), - None => Ok(None), - } - } - - /// Call `Reader::lookup_offset_id` for each section, and return the first match. - /// - /// The first element of the tuple is `true` for supplementary sections. - pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(bool, SectionId, R::Offset)> { - None.or_else(|| self.debug_abbrev.lookup_offset_id(id)) - .or_else(|| self.debug_addr.lookup_offset_id(id)) - .or_else(|| self.debug_aranges.lookup_offset_id(id)) - .or_else(|| self.debug_info.lookup_offset_id(id)) - .or_else(|| self.debug_line.lookup_offset_id(id)) - .or_else(|| self.debug_line_str.lookup_offset_id(id)) - .or_else(|| self.debug_str.lookup_offset_id(id)) - .or_else(|| self.debug_str_offsets.lookup_offset_id(id)) - .or_else(|| self.debug_types.lookup_offset_id(id)) - .or_else(|| self.locations.lookup_offset_id(id)) - .or_else(|| self.ranges.lookup_offset_id(id)) - .map(|(id, offset)| (false, id, offset)) - .or_else(|| { - self.sup() - .and_then(|sup| sup.lookup_offset_id(id)) - .map(|(_, id, offset)| (true, id, offset)) - }) - } - - /// Returns a string representation of the given error. - /// - /// This uses information from the DWARF sections to provide more information in some cases. - pub fn format_error(&self, err: Error) -> String { - #[allow(clippy::single_match)] - match err { - Error::UnexpectedEof(id) => match self.lookup_offset_id(id) { - Some((sup, section, offset)) => { - return format!( - "{} at {}{}+0x{:x}", - err, - section.name(), - if sup { "(sup)" } else { "" }, - offset.into_u64(), - ); - } - None => {} - }, - _ => {} - } - err.description().into() - } -} - -impl<R: Clone> Dwarf<R> { - /// Assuming `self` was loaded from a .dwo, take the appropriate - /// sections from `parent` (which contains the skeleton unit for this - /// dwo) such as `.debug_addr` and merge them into this `Dwarf`. - pub fn make_dwo(&mut self, parent: &Dwarf<R>) { - self.file_type = DwarfFileType::Dwo; - // These sections are always taken from the parent file and not the dwo. - self.debug_addr = parent.debug_addr.clone(); - // .debug_rnglists comes from the DWO, .debug_ranges comes from the - // parent file. - self.ranges - .set_debug_ranges(parent.ranges.debug_ranges().clone()); - self.sup = parent.sup.clone(); - } -} - -/// The sections from a `.dwp` file. -#[derive(Debug)] -pub struct DwarfPackage<R: Reader> { - /// The compilation unit index in the `.debug_cu_index` section. - pub cu_index: UnitIndex<R>, - - /// The type unit index in the `.debug_tu_index` section. - pub tu_index: UnitIndex<R>, - - /// The `.debug_abbrev.dwo` section. - pub debug_abbrev: DebugAbbrev<R>, - - /// The `.debug_info.dwo` section. - pub debug_info: DebugInfo<R>, - - /// The `.debug_line.dwo` section. - pub debug_line: DebugLine<R>, - - /// The `.debug_str.dwo` section. - pub debug_str: DebugStr<R>, - - /// The `.debug_str_offsets.dwo` section. - pub debug_str_offsets: DebugStrOffsets<R>, - - /// The `.debug_loc.dwo` section. - /// - /// Only present when using GNU split-dwarf extension to DWARF 4. - pub debug_loc: DebugLoc<R>, - - /// The `.debug_loclists.dwo` section. - pub debug_loclists: DebugLocLists<R>, - - /// The `.debug_rnglists.dwo` section. - pub debug_rnglists: DebugRngLists<R>, - - /// The `.debug_types.dwo` section. - /// - /// Only present when using GNU split-dwarf extension to DWARF 4. - pub debug_types: DebugTypes<R>, - - /// An empty section. - /// - /// Used when creating `Dwarf<R>`. - pub empty: R, -} - -impl<R: Reader> DwarfPackage<R> { - /// Try to load the `.dwp` sections using the given loader function. - /// - /// `section` loads a DWARF section from the object file. - /// It should return an empty section if the section does not exist. - pub fn load<F, E>(mut section: F, empty: R) -> core::result::Result<Self, E> - where - F: FnMut(SectionId) -> core::result::Result<R, E>, - E: From<Error>, - { - Ok(DwarfPackage { - cu_index: DebugCuIndex::load(&mut section)?.index()?, - tu_index: DebugTuIndex::load(&mut section)?.index()?, - // Section types are inferred. - debug_abbrev: Section::load(&mut section)?, - debug_info: Section::load(&mut section)?, - debug_line: Section::load(&mut section)?, - debug_str: Section::load(&mut section)?, - debug_str_offsets: Section::load(&mut section)?, - debug_loc: Section::load(&mut section)?, - debug_loclists: Section::load(&mut section)?, - debug_rnglists: Section::load(&mut section)?, - debug_types: Section::load(&mut section)?, - empty, - }) - } - - /// Find the compilation unit with the given DWO identifier and return its section - /// contributions. - pub fn find_cu(&self, id: DwoId, parent: &Dwarf<R>) -> Result<Option<Dwarf<R>>> { - let row = match self.cu_index.find(id.0) { - Some(row) => row, - None => return Ok(None), - }; - self.cu_sections(row, parent).map(Some) - } - - /// Find the type unit with the given type signature and return its section - /// contributions. - pub fn find_tu( - &self, - signature: DebugTypeSignature, - parent: &Dwarf<R>, - ) -> Result<Option<Dwarf<R>>> { - let row = match self.tu_index.find(signature.0) { - Some(row) => row, - None => return Ok(None), - }; - self.tu_sections(row, parent).map(Some) - } - - /// Return the section contributions of the compilation unit at the given index. - /// - /// The index must be in the range `1..cu_index.unit_count`. - /// - /// This function should only be needed by low level parsers. - pub fn cu_sections(&self, index: u32, parent: &Dwarf<R>) -> Result<Dwarf<R>> { - self.sections(self.cu_index.sections(index)?, parent) - } - - /// Return the section contributions of the compilation unit at the given index. - /// - /// The index must be in the range `1..tu_index.unit_count`. - /// - /// This function should only be needed by low level parsers. - pub fn tu_sections(&self, index: u32, parent: &Dwarf<R>) -> Result<Dwarf<R>> { - self.sections(self.tu_index.sections(index)?, parent) - } - - /// Return the section contributions of a unit. - /// - /// This function should only be needed by low level parsers. - pub fn sections( - &self, - sections: UnitIndexSectionIterator<R>, - parent: &Dwarf<R>, - ) -> Result<Dwarf<R>> { - let mut abbrev_offset = 0; - let mut abbrev_size = 0; - let mut info_offset = 0; - let mut info_size = 0; - let mut line_offset = 0; - let mut line_size = 0; - let mut loc_offset = 0; - let mut loc_size = 0; - let mut loclists_offset = 0; - let mut loclists_size = 0; - let mut str_offsets_offset = 0; - let mut str_offsets_size = 0; - let mut rnglists_offset = 0; - let mut rnglists_size = 0; - let mut types_offset = 0; - let mut types_size = 0; - for section in sections { - match section.section { - SectionId::DebugAbbrev => { - abbrev_offset = section.offset; - abbrev_size = section.size; - } - SectionId::DebugInfo => { - info_offset = section.offset; - info_size = section.size; - } - SectionId::DebugLine => { - line_offset = section.offset; - line_size = section.size; - } - SectionId::DebugLoc => { - loc_offset = section.offset; - loc_size = section.size; - } - SectionId::DebugLocLists => { - loclists_offset = section.offset; - loclists_size = section.size; - } - SectionId::DebugStrOffsets => { - str_offsets_offset = section.offset; - str_offsets_size = section.size; - } - SectionId::DebugRngLists => { - rnglists_offset = section.offset; - rnglists_size = section.size; - } - SectionId::DebugTypes => { - types_offset = section.offset; - types_size = section.size; - } - SectionId::DebugMacro | SectionId::DebugMacinfo => { - // These are valid but we can't parse these yet. - } - _ => return Err(Error::UnknownIndexSection), - } - } - - let debug_abbrev = self.debug_abbrev.dwp_range(abbrev_offset, abbrev_size)?; - let debug_info = self.debug_info.dwp_range(info_offset, info_size)?; - let debug_line = self.debug_line.dwp_range(line_offset, line_size)?; - let debug_loc = self.debug_loc.dwp_range(loc_offset, loc_size)?; - let debug_loclists = self - .debug_loclists - .dwp_range(loclists_offset, loclists_size)?; - let debug_str_offsets = self - .debug_str_offsets - .dwp_range(str_offsets_offset, str_offsets_size)?; - let debug_rnglists = self - .debug_rnglists - .dwp_range(rnglists_offset, rnglists_size)?; - let debug_types = self.debug_types.dwp_range(types_offset, types_size)?; - - let debug_str = self.debug_str.clone(); - - let debug_addr = parent.debug_addr.clone(); - let debug_ranges = parent.ranges.debug_ranges().clone(); - - let debug_aranges = self.empty.clone().into(); - let debug_line_str = self.empty.clone().into(); - - Ok(Dwarf { - debug_abbrev, - debug_addr, - debug_aranges, - debug_info, - debug_line, - debug_line_str, - debug_str, - debug_str_offsets, - debug_types, - locations: LocationLists::new(debug_loc, debug_loclists), - ranges: RangeLists::new(debug_ranges, debug_rnglists), - file_type: DwarfFileType::Dwo, - sup: parent.sup.clone(), - abbreviations_cache: AbbreviationsCache::new(), - }) - } -} - -/// All of the commonly used information for a unit in the `.debug_info` or `.debug_types` -/// sections. -#[derive(Debug)] -pub struct Unit<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// The header of the unit. - pub header: UnitHeader<R, Offset>, - - /// The parsed abbreviations for the unit. - pub abbreviations: Arc<Abbreviations>, - - /// The `DW_AT_name` attribute of the unit. - pub name: Option<R>, - - /// The `DW_AT_comp_dir` attribute of the unit. - pub comp_dir: Option<R>, - - /// The `DW_AT_low_pc` attribute of the unit. Defaults to 0. - pub low_pc: u64, - - /// The `DW_AT_str_offsets_base` attribute of the unit. Defaults to 0. - pub str_offsets_base: DebugStrOffsetsBase<Offset>, - - /// The `DW_AT_addr_base` attribute of the unit. Defaults to 0. - pub addr_base: DebugAddrBase<Offset>, - - /// The `DW_AT_loclists_base` attribute of the unit. Defaults to 0. - pub loclists_base: DebugLocListsBase<Offset>, - - /// The `DW_AT_rnglists_base` attribute of the unit. Defaults to 0. - pub rnglists_base: DebugRngListsBase<Offset>, - - /// The line number program of the unit. - pub line_program: Option<IncompleteLineProgram<R, Offset>>, - - /// The DWO ID of a skeleton unit or split compilation unit. - pub dwo_id: Option<DwoId>, -} - -impl<R: Reader> Unit<R> { - /// Construct a new `Unit` from the given unit header. - #[inline] - pub fn new(dwarf: &Dwarf<R>, header: UnitHeader<R>) -> Result<Self> { - let abbreviations = dwarf.abbreviations(&header)?; - Self::new_with_abbreviations(dwarf, header, abbreviations) - } - - /// Construct a new `Unit` from the given unit header and abbreviations. - /// - /// The abbreviations for this call can be obtained using `dwarf.abbreviations(&header)`. - /// The caller may implement caching to reuse the `Abbreviations` across units with the - /// same `header.debug_abbrev_offset()` value. - #[inline] - pub fn new_with_abbreviations( - dwarf: &Dwarf<R>, - header: UnitHeader<R>, - abbreviations: Arc<Abbreviations>, - ) -> Result<Self> { - let mut unit = Unit { - abbreviations, - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase::default_for_encoding_and_file( - header.encoding(), - dwarf.file_type, - ), - // NB: Because the .debug_addr section never lives in a .dwo, we can assume its base is always 0 or provided. - addr_base: DebugAddrBase(R::Offset::from_u8(0)), - loclists_base: DebugLocListsBase::default_for_encoding_and_file( - header.encoding(), - dwarf.file_type, - ), - rnglists_base: DebugRngListsBase::default_for_encoding_and_file( - header.encoding(), - dwarf.file_type, - ), - line_program: None, - dwo_id: match header.type_() { - UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => Some(dwo_id), - _ => None, - }, - header, - }; - let mut name = None; - let mut comp_dir = None; - let mut line_program_offset = None; - let mut low_pc_attr = None; - - { - let mut cursor = unit.header.entries(&unit.abbreviations); - cursor.next_dfs()?; - let root = cursor.current().ok_or(Error::MissingUnitDie)?; - let mut attrs = root.attrs(); - while let Some(attr) = attrs.next()? { - match attr.name() { - constants::DW_AT_name => { - name = Some(attr.value()); - } - constants::DW_AT_comp_dir => { - comp_dir = Some(attr.value()); - } - constants::DW_AT_low_pc => { - low_pc_attr = Some(attr.value()); - } - constants::DW_AT_stmt_list => { - if let AttributeValue::DebugLineRef(offset) = attr.value() { - line_program_offset = Some(offset); - } - } - constants::DW_AT_str_offsets_base => { - if let AttributeValue::DebugStrOffsetsBase(base) = attr.value() { - unit.str_offsets_base = base; - } - } - constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => { - if let AttributeValue::DebugAddrBase(base) = attr.value() { - unit.addr_base = base; - } - } - constants::DW_AT_loclists_base => { - if let AttributeValue::DebugLocListsBase(base) = attr.value() { - unit.loclists_base = base; - } - } - constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => { - if let AttributeValue::DebugRngListsBase(base) = attr.value() { - unit.rnglists_base = base; - } - } - constants::DW_AT_GNU_dwo_id => { - if unit.dwo_id.is_none() { - if let AttributeValue::DwoId(dwo_id) = attr.value() { - unit.dwo_id = Some(dwo_id); - } - } - } - _ => {} - } - } - } - - unit.name = match name { - Some(val) => dwarf.attr_string(&unit, val).ok(), - None => None, - }; - unit.comp_dir = match comp_dir { - Some(val) => dwarf.attr_string(&unit, val).ok(), - None => None, - }; - unit.line_program = match line_program_offset { - Some(offset) => Some(dwarf.debug_line.program( - offset, - unit.header.address_size(), - unit.comp_dir.clone(), - unit.name.clone(), - )?), - None => None, - }; - if let Some(low_pc_attr) = low_pc_attr { - if let Some(addr) = dwarf.attr_address(&unit, low_pc_attr)? { - unit.low_pc = addr; - } - } - Ok(unit) - } - - /// Return the encoding parameters for this unit. - #[inline] - pub fn encoding(&self) -> Encoding { - self.header.encoding() - } - - /// Read the `DebuggingInformationEntry` at the given offset. - pub fn entry(&self, offset: UnitOffset<R::Offset>) -> Result<DebuggingInformationEntry<R>> { - self.header.entry(&self.abbreviations, offset) - } - - /// Navigate this unit's `DebuggingInformationEntry`s. - #[inline] - pub fn entries(&self) -> EntriesCursor<R> { - self.header.entries(&self.abbreviations) - } - - /// Navigate this unit's `DebuggingInformationEntry`s - /// starting at the given offset. - #[inline] - pub fn entries_at_offset(&self, offset: UnitOffset<R::Offset>) -> Result<EntriesCursor<R>> { - self.header.entries_at_offset(&self.abbreviations, offset) - } - - /// Navigate this unit's `DebuggingInformationEntry`s as a tree - /// starting at the given offset. - #[inline] - pub fn entries_tree(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesTree<R>> { - self.header.entries_tree(&self.abbreviations, offset) - } - - /// Read the raw data that defines the Debugging Information Entries. - #[inline] - pub fn entries_raw(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesRaw<R>> { - self.header.entries_raw(&self.abbreviations, offset) - } - - /// Copy attributes that are subject to relocation from another unit. This is intended - /// to be used to copy attributes from a skeleton compilation unit to the corresponding - /// split compilation unit. - pub fn copy_relocated_attributes(&mut self, other: &Unit<R>) { - self.low_pc = other.low_pc; - self.addr_base = other.addr_base; - if self.header.version() < 5 { - self.rnglists_base = other.rnglists_base; - } - } - - /// Find the dwo name (if any) for this unit, automatically handling the differences - /// between the standardized DWARF 5 split DWARF format and the pre-DWARF 5 GNU - /// extension. - /// - /// The returned value is relative to this unit's `comp_dir`. - pub fn dwo_name(&self) -> Result<Option<AttributeValue<R>>> { - let mut entries = self.entries(); - if let None = entries.next_entry()? { - return Ok(None); - } - - let entry = entries.current().unwrap(); - if self.header.version() < 5 { - entry.attr_value(constants::DW_AT_GNU_dwo_name) - } else { - entry.attr_value(constants::DW_AT_dwo_name) - } - } -} - -impl<T: ReaderOffset> UnitSectionOffset<T> { - /// Convert an offset to be relative to the start of the given unit, - /// instead of relative to the start of the section. - /// Returns `None` if the offset is not within the unit entries. - pub fn to_unit_offset<R>(&self, unit: &Unit<R>) -> Option<UnitOffset<T>> - where - R: Reader<Offset = T>, - { - let (offset, unit_offset) = match (self, unit.header.offset()) { - ( - UnitSectionOffset::DebugInfoOffset(offset), - UnitSectionOffset::DebugInfoOffset(unit_offset), - ) => (offset.0, unit_offset.0), - ( - UnitSectionOffset::DebugTypesOffset(offset), - UnitSectionOffset::DebugTypesOffset(unit_offset), - ) => (offset.0, unit_offset.0), - _ => return None, - }; - let offset = match offset.checked_sub(unit_offset) { - Some(offset) => UnitOffset(offset), - None => return None, - }; - if !unit.header.is_valid_offset(offset) { - return None; - } - Some(offset) - } -} - -impl<T: ReaderOffset> UnitOffset<T> { - /// Convert an offset to be relative to the start of the .debug_info section, - /// instead of relative to the start of the given compilation unit. - /// - /// Does not check that the offset is valid. - pub fn to_unit_section_offset<R>(&self, unit: &Unit<R>) -> UnitSectionOffset<T> - where - R: Reader<Offset = T>, - { - match unit.header.offset() { - UnitSectionOffset::DebugInfoOffset(unit_offset) => { - DebugInfoOffset(unit_offset.0 + self.0).into() - } - UnitSectionOffset::DebugTypesOffset(unit_offset) => { - DebugTypesOffset(unit_offset.0 + self.0).into() - } - } - } -} - -/// An iterator for the address ranges of a `DebuggingInformationEntry`. -/// -/// Returned by `Dwarf::die_ranges` and `Dwarf::unit_ranges`. -#[derive(Debug)] -pub struct RangeIter<R: Reader>(RangeIterInner<R>); - -#[derive(Debug)] -enum RangeIterInner<R: Reader> { - Single(Option<Range>), - List(RngListIter<R>), -} - -impl<R: Reader> Default for RangeIter<R> { - fn default() -> Self { - RangeIter(RangeIterInner::Single(None)) - } -} - -impl<R: Reader> RangeIter<R> { - /// Advance the iterator to the next range. - pub fn next(&mut self) -> Result<Option<Range>> { - match self.0 { - RangeIterInner::Single(ref mut range) => Ok(range.take()), - RangeIterInner::List(ref mut list) => list.next(), - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for RangeIter<R> { - type Item = Range; - type Error = Error; - - #[inline] - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - RangeIter::next(self) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::read::EndianSlice; - use crate::{Endianity, LittleEndian}; - - /// Ensure that `Dwarf<R>` is covariant wrt R. - #[test] - fn test_dwarf_variance() { - /// This only needs to compile. - fn _f<'a: 'b, 'b, E: Endianity>(x: Dwarf<EndianSlice<'a, E>>) -> Dwarf<EndianSlice<'b, E>> { - x - } - } - - /// Ensure that `Unit<R>` is covariant wrt R. - #[test] - fn test_dwarf_unit_variance() { - /// This only needs to compile. - fn _f<'a: 'b, 'b, E: Endianity>(x: Unit<EndianSlice<'a, E>>) -> Unit<EndianSlice<'b, E>> { - x - } - } - - #[test] - fn test_send() { - fn assert_is_send<T: Send>() {} - assert_is_send::<Dwarf<EndianSlice<LittleEndian>>>(); - assert_is_send::<Unit<EndianSlice<LittleEndian>>>(); - } - - #[test] - fn test_format_error() { - let mut owned_dwarf = Dwarf::load(|_| -> Result<_> { Ok(vec![1, 2]) }).unwrap(); - owned_dwarf - .load_sup(|_| -> Result<_> { Ok(vec![1, 2]) }) - .unwrap(); - let dwarf = owned_dwarf.borrow(|section| EndianSlice::new(§ion, LittleEndian)); - - match dwarf.debug_str.get_str(DebugStrOffset(1)) { - Ok(r) => panic!("Unexpected str {:?}", r), - Err(e) => { - assert_eq!( - dwarf.format_error(e), - "Hit the end of input before it was expected at .debug_str+0x1" - ); - } - } - match dwarf.sup().unwrap().debug_str.get_str(DebugStrOffset(1)) { - Ok(r) => panic!("Unexpected str {:?}", r), - Err(e) => { - assert_eq!( - dwarf.format_error(e), - "Hit the end of input before it was expected at .debug_str(sup)+0x1" - ); - } - } - assert_eq!(dwarf.format_error(Error::Io), Error::Io.description()); - } -} diff --git a/vendor/gimli/src/read/endian_reader.rs b/vendor/gimli/src/read/endian_reader.rs deleted file mode 100644 index 8852b38..0000000 --- a/vendor/gimli/src/read/endian_reader.rs +++ /dev/null @@ -1,639 +0,0 @@ -//! Defining custom `Reader`s quickly. - -use alloc::borrow::Cow; -use alloc::rc::Rc; -use alloc::string::String; -use alloc::sync::Arc; -use core::fmt::Debug; -use core::ops::{Deref, Index, Range, RangeFrom, RangeTo}; -use core::slice; -use core::str; -use stable_deref_trait::CloneStableDeref; - -use crate::endianity::Endianity; -use crate::read::{Error, Reader, ReaderOffsetId, Result}; - -/// A reference counted, non-thread-safe slice of bytes and associated -/// endianity. -/// -/// ``` -/// # #[cfg(feature = "std")] { -/// use std::rc::Rc; -/// -/// let buf = Rc::from(&[1, 2, 3, 4][..]); -/// let reader = gimli::EndianRcSlice::new(buf, gimli::NativeEndian); -/// # let _ = reader; -/// # } -/// ``` -pub type EndianRcSlice<Endian> = EndianReader<Endian, Rc<[u8]>>; - -/// An atomically reference counted, thread-safe slice of bytes and associated -/// endianity. -/// -/// ``` -/// # #[cfg(feature = "std")] { -/// use std::sync::Arc; -/// -/// let buf = Arc::from(&[1, 2, 3, 4][..]); -/// let reader = gimli::EndianArcSlice::new(buf, gimli::NativeEndian); -/// # let _ = reader; -/// # } -/// ``` -pub type EndianArcSlice<Endian> = EndianReader<Endian, Arc<[u8]>>; - -/// An easy way to define a custom `Reader` implementation with a reference to a -/// generic buffer of bytes and an associated endianity. -/// -/// Note that the whole original buffer is kept alive in memory even if there is -/// only one reader that references only a handful of bytes from that original -/// buffer. That is, `EndianReader` will not do any copying, moving, or -/// compacting in order to free up unused regions of the original buffer. If you -/// require this kind of behavior, it is up to you to implement `Reader` -/// directly by-hand. -/// -/// # Example -/// -/// Say you have an `mmap`ed file that you want to serve as a `gimli::Reader`. -/// You can wrap that `mmap`ed file up in a `MmapFile` type and use -/// `EndianReader<Rc<MmapFile>>` or `EndianReader<Arc<MmapFile>>` as readers as -/// long as `MmapFile` dereferences to the underlying `[u8]` data. -/// -/// ``` -/// use std::io; -/// use std::ops::Deref; -/// use std::path::Path; -/// use std::slice; -/// use std::sync::Arc; -/// -/// /// A type that represents an `mmap`ed file. -/// #[derive(Debug)] -/// pub struct MmapFile { -/// ptr: *const u8, -/// len: usize, -/// } -/// -/// impl MmapFile { -/// pub fn new(path: &Path) -> io::Result<MmapFile> { -/// // Call `mmap` and check for errors and all that... -/// # unimplemented!() -/// } -/// } -/// -/// impl Drop for MmapFile { -/// fn drop(&mut self) { -/// // Call `munmap` to clean up after ourselves... -/// # unimplemented!() -/// } -/// } -/// -/// // And `MmapFile` can deref to a slice of the `mmap`ed region of memory. -/// impl Deref for MmapFile { -/// type Target = [u8]; -/// fn deref(&self) -> &[u8] { -/// unsafe { -/// slice::from_raw_parts(self.ptr, self.len) -/// } -/// } -/// } -/// -/// /// A type that represents a shared `mmap`ed file. -/// #[derive(Debug, Clone)] -/// pub struct ArcMmapFile(Arc<MmapFile>); -/// -/// // And `ArcMmapFile` can deref to a slice of the `mmap`ed region of memory. -/// impl Deref for ArcMmapFile { -/// type Target = [u8]; -/// fn deref(&self) -> &[u8] { -/// &self.0 -/// } -/// } -/// -/// // These are both valid for any `Rc` or `Arc`. -/// unsafe impl gimli::StableDeref for ArcMmapFile {} -/// unsafe impl gimli::CloneStableDeref for ArcMmapFile {} -/// -/// /// A `gimli::Reader` that is backed by an `mmap`ed file! -/// pub type MmapFileReader<Endian> = gimli::EndianReader<Endian, ArcMmapFile>; -/// # fn test(_: &MmapFileReader<gimli::NativeEndian>) { } -/// ``` -#[derive(Debug, Clone, Copy, Hash)] -pub struct EndianReader<Endian, T> -where - Endian: Endianity, - T: CloneStableDeref<Target = [u8]> + Debug, -{ - range: SubRange<T>, - endian: Endian, -} - -impl<Endian, T1, T2> PartialEq<EndianReader<Endian, T2>> for EndianReader<Endian, T1> -where - Endian: Endianity, - T1: CloneStableDeref<Target = [u8]> + Debug, - T2: CloneStableDeref<Target = [u8]> + Debug, -{ - fn eq(&self, rhs: &EndianReader<Endian, T2>) -> bool { - self.bytes() == rhs.bytes() - } -} - -impl<Endian, T> Eq for EndianReader<Endian, T> -where - Endian: Endianity, - T: CloneStableDeref<Target = [u8]> + Debug, -{ -} - -// This is separated out from `EndianReader` so that we can avoid running afoul -// of borrowck. We need to `read_slice(&mut self, ...) -> &[u8]` and then call -// `self.endian.read_whatever` on the result. The problem is that the returned -// slice keeps the `&mut self` borrow active, so we wouldn't be able to access -// `self.endian`. Splitting the sub-range out from the endian lets us work -// around this, making it so that only the `self.range` borrow is held active, -// not all of `self`. -// -// This also serves to encapsulate the unsafe code concerning `CloneStableDeref`. -// The `bytes` member is held so that the bytes live long enough, and the -// `CloneStableDeref` ensures these bytes never move. The `ptr` and `len` -// members point inside `bytes`, and are updated during read operations. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -struct SubRange<T> -where - T: CloneStableDeref<Target = [u8]> + Debug, -{ - bytes: T, - ptr: *const u8, - len: usize, -} - -unsafe impl<T> Send for SubRange<T> where T: CloneStableDeref<Target = [u8]> + Debug + Send {} - -unsafe impl<T> Sync for SubRange<T> where T: CloneStableDeref<Target = [u8]> + Debug + Sync {} - -impl<T> SubRange<T> -where - T: CloneStableDeref<Target = [u8]> + Debug, -{ - #[inline] - fn new(bytes: T) -> Self { - let ptr = bytes.as_ptr(); - let len = bytes.len(); - SubRange { bytes, ptr, len } - } - - #[inline] - fn bytes(&self) -> &[u8] { - // Safe because `T` implements `CloneStableDeref`, `bytes` can't be modified, - // and all operations that modify `ptr` and `len` ensure they stay in range. - unsafe { slice::from_raw_parts(self.ptr, self.len) } - } - - #[inline] - fn len(&self) -> usize { - self.len - } - - #[inline] - fn truncate(&mut self, len: usize) { - assert!(len <= self.len); - self.len = len; - } - - #[inline] - fn skip(&mut self, len: usize) { - assert!(len <= self.len); - self.ptr = unsafe { self.ptr.add(len) }; - self.len -= len; - } - - #[inline] - fn read_slice(&mut self, len: usize) -> Option<&[u8]> { - if self.len() < len { - None - } else { - // Same as for `bytes()`. - let bytes = unsafe { slice::from_raw_parts(self.ptr, len) }; - self.skip(len); - Some(bytes) - } - } -} - -impl<Endian, T> EndianReader<Endian, T> -where - Endian: Endianity, - T: CloneStableDeref<Target = [u8]> + Debug, -{ - /// Construct a new `EndianReader` with the given bytes. - #[inline] - pub fn new(bytes: T, endian: Endian) -> EndianReader<Endian, T> { - EndianReader { - range: SubRange::new(bytes), - endian, - } - } - - /// Return a reference to the raw bytes underlying this reader. - #[inline] - pub fn bytes(&self) -> &[u8] { - self.range.bytes() - } -} - -/// # Range Methods -/// -/// Unfortunately, `std::ops::Index` *must* return a reference, so we can't -/// implement `Index<Range<usize>>` to return a new `EndianReader` the way we -/// would like to. Instead, we abandon fancy indexing operators and have these -/// plain old methods. -impl<Endian, T> EndianReader<Endian, T> -where - Endian: Endianity, - T: CloneStableDeref<Target = [u8]> + Debug, -{ - /// Take the given `start..end` range of the underlying buffer and return a - /// new `EndianReader`. - /// - /// ``` - /// # #[cfg(feature = "std")] { - /// use gimli::{EndianReader, LittleEndian}; - /// use std::sync::Arc; - /// - /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); - /// let reader = EndianReader::new(buf.clone(), LittleEndian); - /// assert_eq!(reader.range(1..3), - /// EndianReader::new(&buf[1..3], LittleEndian)); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics if the range is out of bounds. - pub fn range(&self, idx: Range<usize>) -> EndianReader<Endian, T> { - let mut r = self.clone(); - r.range.skip(idx.start); - r.range.truncate(idx.len()); - r - } - - /// Take the given `start..` range of the underlying buffer and return a new - /// `EndianReader`. - /// - /// ``` - /// # #[cfg(feature = "std")] { - /// use gimli::{EndianReader, LittleEndian}; - /// use std::sync::Arc; - /// - /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); - /// let reader = EndianReader::new(buf.clone(), LittleEndian); - /// assert_eq!(reader.range_from(2..), - /// EndianReader::new(&buf[2..], LittleEndian)); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics if the range is out of bounds. - pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianReader<Endian, T> { - let mut r = self.clone(); - r.range.skip(idx.start); - r - } - - /// Take the given `..end` range of the underlying buffer and return a new - /// `EndianReader`. - /// - /// ``` - /// # #[cfg(feature = "std")] { - /// use gimli::{EndianReader, LittleEndian}; - /// use std::sync::Arc; - /// - /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); - /// let reader = EndianReader::new(buf.clone(), LittleEndian); - /// assert_eq!(reader.range_to(..3), - /// EndianReader::new(&buf[..3], LittleEndian)); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics if the range is out of bounds. - pub fn range_to(&self, idx: RangeTo<usize>) -> EndianReader<Endian, T> { - let mut r = self.clone(); - r.range.truncate(idx.end); - r - } -} - -impl<Endian, T> Index<usize> for EndianReader<Endian, T> -where - Endian: Endianity, - T: CloneStableDeref<Target = [u8]> + Debug, -{ - type Output = u8; - fn index(&self, idx: usize) -> &Self::Output { - &self.bytes()[idx] - } -} - -impl<Endian, T> Index<RangeFrom<usize>> for EndianReader<Endian, T> -where - Endian: Endianity, - T: CloneStableDeref<Target = [u8]> + Debug, -{ - type Output = [u8]; - fn index(&self, idx: RangeFrom<usize>) -> &Self::Output { - &self.bytes()[idx] - } -} - -impl<Endian, T> Deref for EndianReader<Endian, T> -where - Endian: Endianity, - T: CloneStableDeref<Target = [u8]> + Debug, -{ - type Target = [u8]; - fn deref(&self) -> &Self::Target { - self.bytes() - } -} - -impl<Endian, T> Reader for EndianReader<Endian, T> -where - Endian: Endianity, - T: CloneStableDeref<Target = [u8]> + Debug, -{ - type Endian = Endian; - type Offset = usize; - - #[inline] - fn endian(&self) -> Endian { - self.endian - } - - #[inline] - fn len(&self) -> usize { - self.range.len() - } - - #[inline] - fn empty(&mut self) { - self.range.truncate(0); - } - - #[inline] - fn truncate(&mut self, len: usize) -> Result<()> { - if self.len() < len { - Err(Error::UnexpectedEof(self.offset_id())) - } else { - self.range.truncate(len); - Ok(()) - } - } - - #[inline] - fn offset_from(&self, base: &EndianReader<Endian, T>) -> usize { - let base_ptr = base.bytes().as_ptr() as *const u8 as usize; - let ptr = self.bytes().as_ptr() as *const u8 as usize; - debug_assert!(base_ptr <= ptr); - debug_assert!(ptr + self.bytes().len() <= base_ptr + base.bytes().len()); - ptr - base_ptr - } - - #[inline] - fn offset_id(&self) -> ReaderOffsetId { - ReaderOffsetId(self.bytes().as_ptr() as u64) - } - - #[inline] - fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset> { - let id = id.0; - let self_id = self.bytes().as_ptr() as u64; - let self_len = self.bytes().len() as u64; - if id >= self_id && id <= self_id + self_len { - Some((id - self_id) as usize) - } else { - None - } - } - - #[inline] - fn find(&self, byte: u8) -> Result<usize> { - self.bytes() - .iter() - .position(|x| *x == byte) - .ok_or_else(|| Error::UnexpectedEof(self.offset_id())) - } - - #[inline] - fn skip(&mut self, len: usize) -> Result<()> { - if self.len() < len { - Err(Error::UnexpectedEof(self.offset_id())) - } else { - self.range.skip(len); - Ok(()) - } - } - - #[inline] - fn split(&mut self, len: usize) -> Result<Self> { - if self.len() < len { - Err(Error::UnexpectedEof(self.offset_id())) - } else { - let mut r = self.clone(); - r.range.truncate(len); - self.range.skip(len); - Ok(r) - } - } - - #[inline] - fn to_slice(&self) -> Result<Cow<[u8]>> { - Ok(self.bytes().into()) - } - - #[inline] - fn to_string(&self) -> Result<Cow<str>> { - match str::from_utf8(self.bytes()) { - Ok(s) => Ok(s.into()), - _ => Err(Error::BadUtf8), - } - } - - #[inline] - fn to_string_lossy(&self) -> Result<Cow<str>> { - Ok(String::from_utf8_lossy(self.bytes())) - } - - #[inline] - fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { - match self.range.read_slice(buf.len()) { - Some(slice) => { - buf.copy_from_slice(slice); - Ok(()) - } - None => Err(Error::UnexpectedEof(self.offset_id())), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::endianity::NativeEndian; - use crate::read::Reader; - - fn native_reader<T: CloneStableDeref<Target = [u8]> + Debug>( - bytes: T, - ) -> EndianReader<NativeEndian, T> { - EndianReader::new(bytes, NativeEndian) - } - - const BUF: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - - #[test] - fn test_reader_split() { - let mut reader = native_reader(BUF); - let left = reader.split(3).unwrap(); - assert_eq!(left, native_reader(&BUF[..3])); - assert_eq!(reader, native_reader(&BUF[3..])); - } - - #[test] - fn test_reader_split_out_of_bounds() { - let mut reader = native_reader(BUF); - assert!(reader.split(30).is_err()); - } - - #[test] - fn bytes_and_len_and_range_and_eq() { - let reader = native_reader(BUF); - assert_eq!(reader.len(), BUF.len()); - assert_eq!(reader.bytes(), BUF); - assert_eq!(reader, native_reader(BUF)); - - let range = reader.range(2..8); - let buf_range = &BUF[2..8]; - assert_eq!(range.len(), buf_range.len()); - assert_eq!(range.bytes(), buf_range); - assert_ne!(range, native_reader(BUF)); - assert_eq!(range, native_reader(buf_range)); - - let range_from = range.range_from(1..); - let buf_range_from = &buf_range[1..]; - assert_eq!(range_from.len(), buf_range_from.len()); - assert_eq!(range_from.bytes(), buf_range_from); - assert_ne!(range_from, native_reader(BUF)); - assert_eq!(range_from, native_reader(buf_range_from)); - - let range_to = range_from.range_to(..4); - let buf_range_to = &buf_range_from[..4]; - assert_eq!(range_to.len(), buf_range_to.len()); - assert_eq!(range_to.bytes(), buf_range_to); - assert_ne!(range_to, native_reader(BUF)); - assert_eq!(range_to, native_reader(buf_range_to)); - } - - #[test] - fn find() { - let mut reader = native_reader(BUF); - reader.skip(2).unwrap(); - assert_eq!( - reader.find(5), - Ok(BUF[2..].iter().position(|x| *x == 5).unwrap()) - ); - } - - #[test] - fn indexing() { - let mut reader = native_reader(BUF); - reader.skip(2).unwrap(); - assert_eq!(reader[0], BUF[2]); - } - - #[test] - #[should_panic] - fn indexing_out_of_bounds() { - let mut reader = native_reader(BUF); - reader.skip(2).unwrap(); - let _ = reader[900]; - } - - #[test] - fn endian() { - let reader = native_reader(BUF); - assert_eq!(reader.endian(), NativeEndian); - } - - #[test] - fn empty() { - let mut reader = native_reader(BUF); - assert!(!reader.is_empty()); - reader.empty(); - assert!(reader.is_empty()); - assert!(reader.bytes().is_empty()); - } - - #[test] - fn truncate() { - let reader = native_reader(BUF); - let mut reader = reader.range(2..8); - reader.truncate(2).unwrap(); - assert_eq!(reader.bytes(), &BUF[2..4]); - } - - #[test] - fn offset_from() { - let reader = native_reader(BUF); - let sub = reader.range(2..8); - assert_eq!(sub.offset_from(&reader), 2); - } - - #[test] - fn skip() { - let mut reader = native_reader(BUF); - reader.skip(2).unwrap(); - assert_eq!(reader.bytes(), &BUF[2..]); - } - - #[test] - fn to_slice() { - assert_eq!( - native_reader(BUF).range(2..5).to_slice(), - Ok(Cow::from(&BUF[2..5])) - ); - } - - #[test] - fn to_string_ok() { - let buf = b"hello, world!"; - let reader = native_reader(&buf[..]); - let reader = reader.range_from(7..); - assert_eq!(reader.to_string(), Ok(Cow::from("world!"))); - } - - // The rocket emoji (🚀 = [0xf0, 0x9f, 0x9a, 0x80]) but rotated left by one - // to make it invalid UTF-8. - const BAD_UTF8: &[u8] = &[0x9f, 0x9a, 0x80, 0xf0]; - - #[test] - fn to_string_err() { - let reader = native_reader(BAD_UTF8); - assert!(reader.to_string().is_err()); - } - - #[test] - fn to_string_lossy() { - let reader = native_reader(BAD_UTF8); - assert_eq!(reader.to_string_lossy(), Ok(Cow::from("����"))); - } - - #[test] - fn read_u8_array() { - let mut reader = native_reader(BAD_UTF8); - reader.skip(1).unwrap(); - let arr: [u8; 2] = reader.read_u8_array().unwrap(); - assert_eq!(arr, &BAD_UTF8[1..3]); - assert_eq!(reader.bytes(), &BAD_UTF8[3..]); - } -} diff --git a/vendor/gimli/src/read/endian_slice.rs b/vendor/gimli/src/read/endian_slice.rs deleted file mode 100644 index 0db28da..0000000 --- a/vendor/gimli/src/read/endian_slice.rs +++ /dev/null @@ -1,360 +0,0 @@ -//! Working with byte slices that have an associated endianity. - -#[cfg(feature = "read")] -use alloc::borrow::Cow; -#[cfg(feature = "read")] -use alloc::string::String; -use core::fmt; -use core::ops::{Deref, Range, RangeFrom, RangeTo}; -use core::str; - -use crate::endianity::Endianity; -use crate::read::{Error, Reader, ReaderOffsetId, Result}; - -/// A `&[u8]` slice with endianity metadata. -/// -/// This implements the `Reader` trait, which is used for all reading of DWARF sections. -#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)] -pub struct EndianSlice<'input, Endian> -where - Endian: Endianity, -{ - slice: &'input [u8], - endian: Endian, -} - -impl<'input, Endian> EndianSlice<'input, Endian> -where - Endian: Endianity, -{ - /// Construct a new `EndianSlice` with the given slice and endianity. - #[inline] - pub fn new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian> { - EndianSlice { slice, endian } - } - - /// Return a reference to the raw slice. - #[inline] - #[doc(hidden)] - #[deprecated(note = "Method renamed to EndianSlice::slice; use that instead.")] - pub fn buf(&self) -> &'input [u8] { - self.slice - } - - /// Return a reference to the raw slice. - #[inline] - pub fn slice(&self) -> &'input [u8] { - self.slice - } - - /// Split the slice in two at the given index, resulting in the tuple where - /// the first item has range [0, idx), and the second has range [idx, - /// len). Panics if the index is out of bounds. - #[inline] - pub fn split_at( - &self, - idx: usize, - ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) { - (self.range_to(..idx), self.range_from(idx..)) - } - - /// Find the first occurrence of a byte in the slice, and return its index. - #[inline] - pub fn find(&self, byte: u8) -> Option<usize> { - self.slice.iter().position(|ch| *ch == byte) - } - - /// Return the offset of the start of the slice relative to the start - /// of the given slice. - #[inline] - pub fn offset_from(&self, base: EndianSlice<'input, Endian>) -> usize { - let base_ptr = base.slice.as_ptr() as *const u8 as usize; - let ptr = self.slice.as_ptr() as *const u8 as usize; - debug_assert!(base_ptr <= ptr); - debug_assert!(ptr + self.slice.len() <= base_ptr + base.slice.len()); - ptr - base_ptr - } - - /// Converts the slice to a string using `str::from_utf8`. - /// - /// Returns an error if the slice contains invalid characters. - #[inline] - pub fn to_string(&self) -> Result<&'input str> { - str::from_utf8(self.slice).map_err(|_| Error::BadUtf8) - } - - /// Converts the slice to a string, including invalid characters, - /// using `String::from_utf8_lossy`. - #[cfg(feature = "read")] - #[inline] - pub fn to_string_lossy(&self) -> Cow<'input, str> { - String::from_utf8_lossy(self.slice) - } - - #[inline] - fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> { - if self.slice.len() < len { - Err(Error::UnexpectedEof(self.offset_id())) - } else { - let val = &self.slice[..len]; - self.slice = &self.slice[len..]; - Ok(val) - } - } -} - -/// # Range Methods -/// -/// Unfortunately, `std::ops::Index` *must* return a reference, so we can't -/// implement `Index<Range<usize>>` to return a new `EndianSlice` the way we would -/// like to. Instead, we abandon fancy indexing operators and have these plain -/// old methods. -impl<'input, Endian> EndianSlice<'input, Endian> -where - Endian: Endianity, -{ - /// Take the given `start..end` range of the underlying slice and return a - /// new `EndianSlice`. - /// - /// ``` - /// use gimli::{EndianSlice, LittleEndian}; - /// - /// let slice = &[0x01, 0x02, 0x03, 0x04]; - /// let endian_slice = EndianSlice::new(slice, LittleEndian); - /// assert_eq!(endian_slice.range(1..3), - /// EndianSlice::new(&slice[1..3], LittleEndian)); - /// ``` - pub fn range(&self, idx: Range<usize>) -> EndianSlice<'input, Endian> { - EndianSlice { - slice: &self.slice[idx], - endian: self.endian, - } - } - - /// Take the given `start..` range of the underlying slice and return a new - /// `EndianSlice`. - /// - /// ``` - /// use gimli::{EndianSlice, LittleEndian}; - /// - /// let slice = &[0x01, 0x02, 0x03, 0x04]; - /// let endian_slice = EndianSlice::new(slice, LittleEndian); - /// assert_eq!(endian_slice.range_from(2..), - /// EndianSlice::new(&slice[2..], LittleEndian)); - /// ``` - pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianSlice<'input, Endian> { - EndianSlice { - slice: &self.slice[idx], - endian: self.endian, - } - } - - /// Take the given `..end` range of the underlying slice and return a new - /// `EndianSlice`. - /// - /// ``` - /// use gimli::{EndianSlice, LittleEndian}; - /// - /// let slice = &[0x01, 0x02, 0x03, 0x04]; - /// let endian_slice = EndianSlice::new(slice, LittleEndian); - /// assert_eq!(endian_slice.range_to(..3), - /// EndianSlice::new(&slice[..3], LittleEndian)); - /// ``` - pub fn range_to(&self, idx: RangeTo<usize>) -> EndianSlice<'input, Endian> { - EndianSlice { - slice: &self.slice[idx], - endian: self.endian, - } - } -} - -impl<'input, Endian> Deref for EndianSlice<'input, Endian> -where - Endian: Endianity, -{ - type Target = [u8]; - fn deref(&self) -> &Self::Target { - self.slice - } -} - -impl<'input, Endian: Endianity> fmt::Debug for EndianSlice<'input, Endian> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> { - fmt.debug_tuple("EndianSlice") - .field(&self.endian) - .field(&DebugBytes(self.slice)) - .finish() - } -} - -struct DebugBytes<'input>(&'input [u8]); - -impl<'input> core::fmt::Debug for DebugBytes<'input> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> { - let mut list = fmt.debug_list(); - list.entries(self.0.iter().take(8).copied().map(DebugByte)); - if self.0.len() > 8 { - list.entry(&DebugLen(self.0.len())); - } - list.finish() - } -} - -struct DebugByte(u8); - -impl fmt::Debug for DebugByte { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "0x{:02x}", self.0) - } -} - -struct DebugLen(usize); - -impl fmt::Debug for DebugLen { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "...; {}", self.0) - } -} - -impl<'input, Endian> Reader for EndianSlice<'input, Endian> -where - Endian: Endianity, -{ - type Endian = Endian; - type Offset = usize; - - #[inline] - fn endian(&self) -> Endian { - self.endian - } - - #[inline] - fn len(&self) -> usize { - self.slice.len() - } - - #[inline] - fn is_empty(&self) -> bool { - self.slice.is_empty() - } - - #[inline] - fn empty(&mut self) { - self.slice = &[]; - } - - #[inline] - fn truncate(&mut self, len: usize) -> Result<()> { - if self.slice.len() < len { - Err(Error::UnexpectedEof(self.offset_id())) - } else { - self.slice = &self.slice[..len]; - Ok(()) - } - } - - #[inline] - fn offset_from(&self, base: &Self) -> usize { - self.offset_from(*base) - } - - #[inline] - fn offset_id(&self) -> ReaderOffsetId { - ReaderOffsetId(self.slice.as_ptr() as u64) - } - - #[inline] - fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset> { - let id = id.0; - let self_id = self.slice.as_ptr() as u64; - let self_len = self.slice.len() as u64; - if id >= self_id && id <= self_id + self_len { - Some((id - self_id) as usize) - } else { - None - } - } - - #[inline] - fn find(&self, byte: u8) -> Result<usize> { - self.find(byte) - .ok_or_else(|| Error::UnexpectedEof(self.offset_id())) - } - - #[inline] - fn skip(&mut self, len: usize) -> Result<()> { - if self.slice.len() < len { - Err(Error::UnexpectedEof(self.offset_id())) - } else { - self.slice = &self.slice[len..]; - Ok(()) - } - } - - #[inline] - fn split(&mut self, len: usize) -> Result<Self> { - let slice = self.read_slice(len)?; - Ok(EndianSlice::new(slice, self.endian)) - } - - #[cfg(not(feature = "read"))] - fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed { - super::reader::seal_if_no_alloc::Sealed - } - - #[cfg(feature = "read")] - #[inline] - fn to_slice(&self) -> Result<Cow<[u8]>> { - Ok(self.slice.into()) - } - - #[cfg(feature = "read")] - #[inline] - fn to_string(&self) -> Result<Cow<str>> { - match str::from_utf8(self.slice) { - Ok(s) => Ok(s.into()), - _ => Err(Error::BadUtf8), - } - } - - #[cfg(feature = "read")] - #[inline] - fn to_string_lossy(&self) -> Result<Cow<str>> { - Ok(String::from_utf8_lossy(self.slice)) - } - - #[inline] - fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { - let slice = self.read_slice(buf.len())?; - buf.copy_from_slice(slice); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::endianity::NativeEndian; - - #[test] - fn test_endian_slice_split_at() { - let endian = NativeEndian; - let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - let eb = EndianSlice::new(slice, endian); - assert_eq!( - eb.split_at(3), - ( - EndianSlice::new(&slice[..3], endian), - EndianSlice::new(&slice[3..], endian) - ) - ); - } - - #[test] - #[should_panic] - fn test_endian_slice_split_at_out_of_bounds() { - let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - let eb = EndianSlice::new(slice, NativeEndian); - eb.split_at(30); - } -} diff --git a/vendor/gimli/src/read/index.rs b/vendor/gimli/src/read/index.rs deleted file mode 100644 index 129eb2f..0000000 --- a/vendor/gimli/src/read/index.rs +++ /dev/null @@ -1,535 +0,0 @@ -use core::slice; - -use crate::common::SectionId; -use crate::constants; -use crate::endianity::Endianity; -use crate::read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section}; - -/// The data in the `.debug_cu_index` section of a `.dwp` file. -/// -/// This section contains the compilation unit index. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugCuIndex<R> { - section: R, -} - -impl<'input, Endian> DebugCuIndex<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugCuIndex` instance from the data in the `.debug_cu_index` - /// section. - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R> Section<R> for DebugCuIndex<R> { - fn id() -> SectionId { - SectionId::DebugCuIndex - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugCuIndex<R> { - fn from(section: R) -> Self { - DebugCuIndex { section } - } -} - -impl<R: Reader> DebugCuIndex<R> { - /// Parse the index header. - pub fn index(self) -> Result<UnitIndex<R>> { - UnitIndex::parse(self.section) - } -} - -/// The data in the `.debug_tu_index` section of a `.dwp` file. -/// -/// This section contains the type unit index. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugTuIndex<R> { - section: R, -} - -impl<'input, Endian> DebugTuIndex<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugTuIndex` instance from the data in the `.debug_tu_index` - /// section. - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R> Section<R> for DebugTuIndex<R> { - fn id() -> SectionId { - SectionId::DebugTuIndex - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugTuIndex<R> { - fn from(section: R) -> Self { - DebugTuIndex { section } - } -} - -impl<R: Reader> DebugTuIndex<R> { - /// Parse the index header. - pub fn index(self) -> Result<UnitIndex<R>> { - UnitIndex::parse(self.section) - } -} - -const SECTION_COUNT_MAX: u8 = 8; - -/// The partially parsed index from a `DebugCuIndex` or `DebugTuIndex`. -#[derive(Debug, Clone)] -pub struct UnitIndex<R: Reader> { - version: u16, - section_count: u32, - unit_count: u32, - slot_count: u32, - hash_ids: R, - hash_rows: R, - // Only `section_count` values are valid. - sections: [SectionId; SECTION_COUNT_MAX as usize], - offsets: R, - sizes: R, -} - -impl<R: Reader> UnitIndex<R> { - fn parse(mut input: R) -> Result<UnitIndex<R>> { - if input.is_empty() { - return Ok(UnitIndex { - version: 5, - section_count: 0, - unit_count: 0, - slot_count: 0, - hash_ids: input.clone(), - hash_rows: input.clone(), - sections: [SectionId::DebugAbbrev; SECTION_COUNT_MAX as usize], - offsets: input.clone(), - sizes: input.clone(), - }); - } - - // GNU split-dwarf extension to DWARF 4 uses a 32-bit version, - // but DWARF 5 uses a 16-bit version followed by 16-bit padding. - let mut original_input = input.clone(); - let version; - if input.read_u32()? == 2 { - version = 2 - } else { - version = original_input.read_u16()?; - if version != 5 { - return Err(Error::UnknownVersion(version.into())); - } - } - - let section_count = input.read_u32()?; - let unit_count = input.read_u32()?; - let slot_count = input.read_u32()?; - if slot_count == 0 || slot_count & (slot_count - 1) != 0 || slot_count <= unit_count { - return Err(Error::InvalidIndexSlotCount); - } - - let hash_ids = input.split(R::Offset::from_u64(u64::from(slot_count) * 8)?)?; - let hash_rows = input.split(R::Offset::from_u64(u64::from(slot_count) * 4)?)?; - - let mut sections = [SectionId::DebugAbbrev; SECTION_COUNT_MAX as usize]; - if section_count > SECTION_COUNT_MAX.into() { - return Err(Error::InvalidIndexSectionCount); - } - for i in 0..section_count { - let section = input.read_u32()?; - sections[i as usize] = if version == 2 { - match constants::DwSectV2(section) { - constants::DW_SECT_V2_INFO => SectionId::DebugInfo, - constants::DW_SECT_V2_TYPES => SectionId::DebugTypes, - constants::DW_SECT_V2_ABBREV => SectionId::DebugAbbrev, - constants::DW_SECT_V2_LINE => SectionId::DebugLine, - constants::DW_SECT_V2_LOC => SectionId::DebugLoc, - constants::DW_SECT_V2_STR_OFFSETS => SectionId::DebugStrOffsets, - constants::DW_SECT_V2_MACINFO => SectionId::DebugMacinfo, - constants::DW_SECT_V2_MACRO => SectionId::DebugMacro, - _ => return Err(Error::UnknownIndexSection), - } - } else { - match constants::DwSect(section) { - constants::DW_SECT_INFO => SectionId::DebugInfo, - constants::DW_SECT_ABBREV => SectionId::DebugAbbrev, - constants::DW_SECT_LINE => SectionId::DebugLine, - constants::DW_SECT_LOCLISTS => SectionId::DebugLocLists, - constants::DW_SECT_STR_OFFSETS => SectionId::DebugStrOffsets, - constants::DW_SECT_MACRO => SectionId::DebugMacro, - constants::DW_SECT_RNGLISTS => SectionId::DebugRngLists, - _ => return Err(Error::UnknownIndexSection), - } - }; - } - - let offsets = input.split(R::Offset::from_u64( - u64::from(unit_count) * u64::from(section_count) * 4, - )?)?; - let sizes = input.split(R::Offset::from_u64( - u64::from(unit_count) * u64::from(section_count) * 4, - )?)?; - - Ok(UnitIndex { - version, - section_count, - unit_count, - slot_count, - hash_ids, - hash_rows, - sections, - offsets, - sizes, - }) - } - - /// Find `id` in the index hash table, and return the row index. - /// - /// `id` may be a compilation unit ID if this index is from `.debug_cu_index`, - /// or a type signature if this index is from `.debug_tu_index`. - pub fn find(&self, id: u64) -> Option<u32> { - if self.slot_count == 0 { - return None; - } - let mask = u64::from(self.slot_count - 1); - let mut hash1 = id & mask; - let hash2 = ((id >> 32) & mask) | 1; - for _ in 0..self.slot_count { - // The length of these arrays was validated in `UnitIndex::parse`. - let mut hash_ids = self.hash_ids.clone(); - hash_ids.skip(R::Offset::from_u64(hash1 * 8).ok()?).ok()?; - let hash_id = hash_ids.read_u64().ok()?; - if hash_id == id { - let mut hash_rows = self.hash_rows.clone(); - hash_rows.skip(R::Offset::from_u64(hash1 * 4).ok()?).ok()?; - let hash_row = hash_rows.read_u32().ok()?; - return Some(hash_row); - } - if hash_id == 0 { - return None; - } - hash1 = (hash1 + hash2) & mask; - } - None - } - - /// Return the section offsets and sizes for the given row index. - pub fn sections(&self, mut row: u32) -> Result<UnitIndexSectionIterator<R>> { - if row == 0 { - return Err(Error::InvalidIndexRow); - } - row -= 1; - if row >= self.unit_count { - return Err(Error::InvalidIndexRow); - } - let mut offsets = self.offsets.clone(); - offsets.skip(R::Offset::from_u64( - u64::from(row) * u64::from(self.section_count) * 4, - )?)?; - let mut sizes = self.sizes.clone(); - sizes.skip(R::Offset::from_u64( - u64::from(row) * u64::from(self.section_count) * 4, - )?)?; - Ok(UnitIndexSectionIterator { - sections: self.sections[..self.section_count as usize].iter(), - offsets, - sizes, - }) - } - - /// Return the version. - pub fn version(&self) -> u16 { - self.version - } - - /// Return the number of sections. - pub fn section_count(&self) -> u32 { - self.section_count - } - - /// Return the number of units. - pub fn unit_count(&self) -> u32 { - self.unit_count - } - - /// Return the number of slots. - pub fn slot_count(&self) -> u32 { - self.slot_count - } -} - -/// An iterator over the section offsets and sizes for a row in a `UnitIndex`. -#[derive(Debug, Clone)] -pub struct UnitIndexSectionIterator<'index, R: Reader> { - sections: slice::Iter<'index, SectionId>, - offsets: R, - sizes: R, -} - -impl<'index, R: Reader> Iterator for UnitIndexSectionIterator<'index, R> { - type Item = UnitIndexSection; - - fn next(&mut self) -> Option<UnitIndexSection> { - let section = *self.sections.next()?; - // The length of these arrays was validated in `UnitIndex::parse`. - let offset = self.offsets.read_u32().ok()?; - let size = self.sizes.read_u32().ok()?; - Some(UnitIndexSection { - section, - offset, - size, - }) - } -} - -/// Information about a unit's contribution to a section in a `.dwp` file. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct UnitIndexSection { - /// The section kind. - pub section: SectionId, - /// The base offset of the unit's contribution to the section. - pub offset: u32, - /// The size of the unit's contribution to the section. - pub size: u32, -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::endianity::BigEndian; - use test_assembler::{Endian, Section}; - - #[test] - fn test_empty() { - let buf = EndianSlice::new(&[], BigEndian); - let index = UnitIndex::parse(buf).unwrap(); - assert!(index.find(0).is_none()); - } - - #[test] - fn test_version_2() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Big) - // Header. - .D32(2).D32(0).D32(0).D32(1) - // Slots. - .D64(0).D32(0); - let buf = section.get_contents().unwrap(); - let buf = EndianSlice::new(&buf, BigEndian); - let index = UnitIndex::parse(buf).unwrap(); - assert_eq!(index.version, 2); - } - - #[test] - fn test_version_5() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Big) - // Header. - .D16(5).D16(0).D32(0).D32(0).D32(1) - // Slots. - .D64(0).D32(0); - let buf = section.get_contents().unwrap(); - let buf = EndianSlice::new(&buf, BigEndian); - let index = UnitIndex::parse(buf).unwrap(); - assert_eq!(index.version, 5); - } - - #[test] - fn test_version_5_invalid() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Big) - // Header. - .D32(5).D32(0).D32(0).D32(1) - // Slots. - .D64(0).D32(0); - let buf = section.get_contents().unwrap(); - let buf = EndianSlice::new(&buf, BigEndian); - assert!(UnitIndex::parse(buf).is_err()); - } - - #[test] - fn test_version_2_sections() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Big) - // Header. - .D32(2).D32(8).D32(1).D32(2) - // Slots. - .D64(0).D64(0).D32(0).D32(0) - // Sections. - .D32(constants::DW_SECT_V2_INFO.0) - .D32(constants::DW_SECT_V2_TYPES.0) - .D32(constants::DW_SECT_V2_ABBREV.0) - .D32(constants::DW_SECT_V2_LINE.0) - .D32(constants::DW_SECT_V2_LOC.0) - .D32(constants::DW_SECT_V2_STR_OFFSETS.0) - .D32(constants::DW_SECT_V2_MACINFO.0) - .D32(constants::DW_SECT_V2_MACRO.0) - // Offsets. - .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17).D32(18) - // Sizes. - .D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27).D32(28); - let buf = section.get_contents().unwrap(); - let buf = EndianSlice::new(&buf, BigEndian); - let index = UnitIndex::parse(buf).unwrap(); - assert_eq!(index.section_count, 8); - assert_eq!( - index.sections, - [ - SectionId::DebugInfo, - SectionId::DebugTypes, - SectionId::DebugAbbrev, - SectionId::DebugLine, - SectionId::DebugLoc, - SectionId::DebugStrOffsets, - SectionId::DebugMacinfo, - SectionId::DebugMacro, - ] - ); - #[rustfmt::skip] - let expect = [ - UnitIndexSection { section: SectionId::DebugInfo, offset: 11, size: 21 }, - UnitIndexSection { section: SectionId::DebugTypes, offset: 12, size: 22 }, - UnitIndexSection { section: SectionId::DebugAbbrev, offset: 13, size: 23 }, - UnitIndexSection { section: SectionId::DebugLine, offset: 14, size: 24 }, - UnitIndexSection { section: SectionId::DebugLoc, offset: 15, size: 25 }, - UnitIndexSection { section: SectionId::DebugStrOffsets, offset: 16, size: 26 }, - UnitIndexSection { section: SectionId::DebugMacinfo, offset: 17, size: 27 }, - UnitIndexSection { section: SectionId::DebugMacro, offset: 18, size: 28 }, - ]; - let mut sections = index.sections(1).unwrap(); - for section in &expect { - assert_eq!(*section, sections.next().unwrap()); - } - assert!(sections.next().is_none()); - } - - #[test] - fn test_version_5_sections() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Big) - // Header. - .D16(5).D16(0).D32(7).D32(1).D32(2) - // Slots. - .D64(0).D64(0).D32(0).D32(0) - // Sections. - .D32(constants::DW_SECT_INFO.0) - .D32(constants::DW_SECT_ABBREV.0) - .D32(constants::DW_SECT_LINE.0) - .D32(constants::DW_SECT_LOCLISTS.0) - .D32(constants::DW_SECT_STR_OFFSETS.0) - .D32(constants::DW_SECT_MACRO.0) - .D32(constants::DW_SECT_RNGLISTS.0) - // Offsets. - .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17) - // Sizes. - .D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27); - let buf = section.get_contents().unwrap(); - let buf = EndianSlice::new(&buf, BigEndian); - let index = UnitIndex::parse(buf).unwrap(); - assert_eq!(index.section_count, 7); - assert_eq!( - index.sections[..7], - [ - SectionId::DebugInfo, - SectionId::DebugAbbrev, - SectionId::DebugLine, - SectionId::DebugLocLists, - SectionId::DebugStrOffsets, - SectionId::DebugMacro, - SectionId::DebugRngLists, - ] - ); - #[rustfmt::skip] - let expect = [ - UnitIndexSection { section: SectionId::DebugInfo, offset: 11, size: 21 }, - UnitIndexSection { section: SectionId::DebugAbbrev, offset: 12, size: 22 }, - UnitIndexSection { section: SectionId::DebugLine, offset: 13, size: 23 }, - UnitIndexSection { section: SectionId::DebugLocLists, offset: 14, size: 24 }, - UnitIndexSection { section: SectionId::DebugStrOffsets, offset: 15, size: 25 }, - UnitIndexSection { section: SectionId::DebugMacro, offset: 16, size: 26 }, - UnitIndexSection { section: SectionId::DebugRngLists, offset: 17, size: 27 }, - ]; - let mut sections = index.sections(1).unwrap(); - for section in &expect { - assert_eq!(*section, sections.next().unwrap()); - } - assert!(sections.next().is_none()); - - assert!(index.sections(0).is_err()); - assert!(index.sections(2).is_err()); - } - - #[test] - fn test_hash() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Big) - // Header. - .D16(5).D16(0).D32(2).D32(3).D32(4) - // Slots. - .D64(0xffff_fff2_ffff_fff1) - .D64(0xffff_fff0_ffff_fff1) - .D64(0xffff_fff1_ffff_fff1) - .D64(0) - .D32(3).D32(1).D32(2).D32(0) - // Sections. - .D32(constants::DW_SECT_INFO.0) - .D32(constants::DW_SECT_ABBREV.0) - // Offsets. - .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0) - // Sizes. - .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0); - let buf = section.get_contents().unwrap(); - let buf = EndianSlice::new(&buf, BigEndian); - let index = UnitIndex::parse(buf).unwrap(); - assert_eq!(index.version(), 5); - assert_eq!(index.slot_count(), 4); - assert_eq!(index.unit_count(), 3); - assert_eq!(index.section_count(), 2); - assert_eq!(index.find(0xffff_fff0_ffff_fff1), Some(1)); - assert_eq!(index.find(0xffff_fff1_ffff_fff1), Some(2)); - assert_eq!(index.find(0xffff_fff2_ffff_fff1), Some(3)); - assert_eq!(index.find(0xffff_fff3_ffff_fff1), None); - } - - #[test] - fn test_cu_index() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Big) - // Header. - .D16(5).D16(0).D32(0).D32(0).D32(1) - // Slots. - .D64(0).D32(0); - let buf = section.get_contents().unwrap(); - let cu_index = DebugCuIndex::new(&buf, BigEndian); - let index = cu_index.index().unwrap(); - assert_eq!(index.version, 5); - } - - #[test] - fn test_tu_index() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Big) - // Header. - .D16(5).D16(0).D32(0).D32(0).D32(1) - // Slots. - .D64(0).D32(0); - let buf = section.get_contents().unwrap(); - let tu_index = DebugTuIndex::new(&buf, BigEndian); - let index = tu_index.index().unwrap(); - assert_eq!(index.version, 5); - } -} diff --git a/vendor/gimli/src/read/line.rs b/vendor/gimli/src/read/line.rs deleted file mode 100644 index 47eae92..0000000 --- a/vendor/gimli/src/read/line.rs +++ /dev/null @@ -1,3130 +0,0 @@ -use alloc::vec::Vec; -use core::fmt; -use core::num::{NonZeroU64, Wrapping}; -use core::result; - -use crate::common::{ - DebugLineOffset, DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsIndex, Encoding, Format, - LineEncoding, SectionId, -}; -use crate::constants; -use crate::endianity::Endianity; -use crate::read::{AttributeValue, EndianSlice, Error, Reader, ReaderOffset, Result, Section}; - -/// The `DebugLine` struct contains the source location to instruction mapping -/// found in the `.debug_line` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugLine<R> { - debug_line_section: R, -} - -impl<'input, Endian> DebugLine<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugLine` instance from the data in the `.debug_line` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_line` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugLine, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_line_section_somehow = || &buf; - /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian); - /// ``` - pub fn new(debug_line_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_line_section, endian)) - } -} - -impl<R: Reader> DebugLine<R> { - /// Parse the line number program whose header is at the given `offset` in the - /// `.debug_line` section. - /// - /// The `address_size` must match the compilation unit that the lines apply to. - /// The `comp_dir` should be from the `DW_AT_comp_dir` attribute of the compilation - /// unit. The `comp_name` should be from the `DW_AT_name` attribute of the - /// compilation unit. - /// - /// ```rust,no_run - /// use gimli::{DebugLine, DebugLineOffset, IncompleteLineProgram, EndianSlice, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_line_section_somehow = || &buf; - /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian); - /// - /// // In a real example, we'd grab the offset via a compilation unit - /// // entry's `DW_AT_stmt_list` attribute, and the address size from that - /// // unit directly. - /// let offset = DebugLineOffset(0); - /// let address_size = 8; - /// - /// let program = debug_line.program(offset, address_size, None, None) - /// .expect("should have found a header at that offset, and parsed it OK"); - /// ``` - pub fn program( - &self, - offset: DebugLineOffset<R::Offset>, - address_size: u8, - comp_dir: Option<R>, - comp_name: Option<R>, - ) -> Result<IncompleteLineProgram<R>> { - let input = &mut self.debug_line_section.clone(); - input.skip(offset.0)?; - let header = LineProgramHeader::parse(input, offset, address_size, comp_dir, comp_name)?; - let program = IncompleteLineProgram { header }; - Ok(program) - } -} - -impl<T> DebugLine<T> { - /// Create a `DebugLine` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugLine<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLine<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.debug_line_section).into() - } -} - -impl<R> Section<R> for DebugLine<R> { - fn id() -> SectionId { - SectionId::DebugLine - } - - fn reader(&self) -> &R { - &self.debug_line_section - } -} - -impl<R> From<R> for DebugLine<R> { - fn from(debug_line_section: R) -> Self { - DebugLine { debug_line_section } - } -} - -/// Deprecated. `LineNumberProgram` has been renamed to `LineProgram`. -#[deprecated(note = "LineNumberProgram has been renamed to LineProgram, use that instead.")] -pub type LineNumberProgram<R, Offset> = dyn LineProgram<R, Offset>; - -/// A `LineProgram` provides access to a `LineProgramHeader` and -/// a way to add files to the files table if necessary. Gimli consumers should -/// never need to use or see this trait. -pub trait LineProgram<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Get a reference to the held `LineProgramHeader`. - fn header(&self) -> &LineProgramHeader<R, Offset>; - /// Add a file to the file table if necessary. - fn add_file(&mut self, file: FileEntry<R, Offset>); -} - -impl<R, Offset> LineProgram<R, Offset> for IncompleteLineProgram<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - fn header(&self) -> &LineProgramHeader<R, Offset> { - &self.header - } - fn add_file(&mut self, file: FileEntry<R, Offset>) { - self.header.file_names.push(file); - } -} - -impl<'program, R, Offset> LineProgram<R, Offset> for &'program CompleteLineProgram<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - fn header(&self) -> &LineProgramHeader<R, Offset> { - &self.header - } - fn add_file(&mut self, _: FileEntry<R, Offset>) { - // Nop. Our file table is already complete. - } -} - -/// Deprecated. `StateMachine` has been renamed to `LineRows`. -#[deprecated(note = "StateMachine has been renamed to LineRows, use that instead.")] -pub type StateMachine<R, Program, Offset> = LineRows<R, Program, Offset>; - -/// Executes a `LineProgram` to iterate over the rows in the matrix of line number information. -/// -/// "The hypothetical machine used by a consumer of the line number information -/// to expand the byte-coded instruction stream into a matrix of line number -/// information." -- Section 6.2.1 -#[derive(Debug, Clone)] -pub struct LineRows<R, Program, Offset = <R as Reader>::Offset> -where - Program: LineProgram<R, Offset>, - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - program: Program, - row: LineRow, - instructions: LineInstructions<R>, -} - -type OneShotLineRows<R, Offset = <R as Reader>::Offset> = - LineRows<R, IncompleteLineProgram<R, Offset>, Offset>; - -type ResumedLineRows<'program, R, Offset = <R as Reader>::Offset> = - LineRows<R, &'program CompleteLineProgram<R, Offset>, Offset>; - -impl<R, Program, Offset> LineRows<R, Program, Offset> -where - Program: LineProgram<R, Offset>, - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - fn new(program: IncompleteLineProgram<R, Offset>) -> OneShotLineRows<R, Offset> { - let row = LineRow::new(program.header()); - let instructions = LineInstructions { - input: program.header().program_buf.clone(), - }; - LineRows { - program, - row, - instructions, - } - } - - fn resume<'program>( - program: &'program CompleteLineProgram<R, Offset>, - sequence: &LineSequence<R>, - ) -> ResumedLineRows<'program, R, Offset> { - let row = LineRow::new(program.header()); - let instructions = sequence.instructions.clone(); - LineRows { - program, - row, - instructions, - } - } - - /// Get a reference to the header for this state machine's line number - /// program. - #[inline] - pub fn header(&self) -> &LineProgramHeader<R, Offset> { - self.program.header() - } - - /// Parse and execute the next instructions in the line number program until - /// another row in the line number matrix is computed. - /// - /// The freshly computed row is returned as `Ok(Some((header, row)))`. - /// If the matrix is complete, and there are no more new rows in the line - /// number matrix, then `Ok(None)` is returned. If there was an error parsing - /// an instruction, then `Err(e)` is returned. - /// - /// Unfortunately, the references mean that this cannot be a - /// `FallibleIterator`. - pub fn next_row(&mut self) -> Result<Option<(&LineProgramHeader<R, Offset>, &LineRow)>> { - // Perform any reset that was required after copying the previous row. - self.row.reset(self.program.header()); - - loop { - // Split the borrow here, rather than calling `self.header()`. - match self.instructions.next_instruction(self.program.header()) { - Err(err) => return Err(err), - Ok(None) => return Ok(None), - Ok(Some(instruction)) => { - if self.row.execute(instruction, &mut self.program) { - if self.row.tombstone { - // Perform any reset that was required for the tombstone row. - // Normally this is done when `next_row` is called again, but for - // tombstones we loop immediately. - self.row.reset(self.program.header()); - } else { - return Ok(Some((self.header(), &self.row))); - } - } - // Fall through, parse the next instruction, and see if that - // yields a row. - } - } - } - } -} - -/// Deprecated. `Opcode` has been renamed to `LineInstruction`. -#[deprecated(note = "Opcode has been renamed to LineInstruction, use that instead.")] -pub type Opcode<R> = LineInstruction<R, <R as Reader>::Offset>; - -/// A parsed line number program instruction. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum LineInstruction<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// > ### 6.2.5.1 Special Opcodes - /// > - /// > Each ubyte special opcode has the following effect on the state machine: - /// > - /// > 1. Add a signed integer to the line register. - /// > - /// > 2. Modify the operation pointer by incrementing the address and - /// > op_index registers as described below. - /// > - /// > 3. Append a row to the matrix using the current values of the state - /// > machine registers. - /// > - /// > 4. Set the basic_block register to “false.” - /// > - /// > 5. Set the prologue_end register to “false.” - /// > - /// > 6. Set the epilogue_begin register to “false.” - /// > - /// > 7. Set the discriminator register to 0. - /// > - /// > All of the special opcodes do those same seven things; they differ from - /// > one another only in what values they add to the line, address and - /// > op_index registers. - Special(u8), - - /// "[`LineInstruction::Copy`] appends a row to the matrix using the current - /// values of the state machine registers. Then it sets the discriminator - /// register to 0, and sets the basic_block, prologue_end and epilogue_begin - /// registers to “false.”" - Copy, - - /// "The DW_LNS_advance_pc opcode takes a single unsigned LEB128 operand as - /// the operation advance and modifies the address and op_index registers - /// [the same as `LineInstruction::Special`]" - AdvancePc(u64), - - /// "The DW_LNS_advance_line opcode takes a single signed LEB128 operand and - /// adds that value to the line register of the state machine." - AdvanceLine(i64), - - /// "The DW_LNS_set_file opcode takes a single unsigned LEB128 operand and - /// stores it in the file register of the state machine." - SetFile(u64), - - /// "The DW_LNS_set_column opcode takes a single unsigned LEB128 operand and - /// stores it in the column register of the state machine." - SetColumn(u64), - - /// "The DW_LNS_negate_stmt opcode takes no operands. It sets the is_stmt - /// register of the state machine to the logical negation of its current - /// value." - NegateStatement, - - /// "The DW_LNS_set_basic_block opcode takes no operands. It sets the - /// basic_block register of the state machine to “true.”" - SetBasicBlock, - - /// > The DW_LNS_const_add_pc opcode takes no operands. It advances the - /// > address and op_index registers by the increments corresponding to - /// > special opcode 255. - /// > - /// > When the line number program needs to advance the address by a small - /// > amount, it can use a single special opcode, which occupies a single - /// > byte. When it needs to advance the address by up to twice the range of - /// > the last special opcode, it can use DW_LNS_const_add_pc followed by a - /// > special opcode, for a total of two bytes. Only if it needs to advance - /// > the address by more than twice that range will it need to use both - /// > DW_LNS_advance_pc and a special opcode, requiring three or more bytes. - ConstAddPc, - - /// > The DW_LNS_fixed_advance_pc opcode takes a single uhalf (unencoded) - /// > operand and adds it to the address register of the state machine and - /// > sets the op_index register to 0. This is the only standard opcode whose - /// > operand is not a variable length number. It also does not multiply the - /// > operand by the minimum_instruction_length field of the header. - FixedAddPc(u16), - - /// "[`LineInstruction::SetPrologueEnd`] sets the prologue_end register to “true”." - SetPrologueEnd, - - /// "[`LineInstruction::SetEpilogueBegin`] sets the epilogue_begin register to - /// “true”." - SetEpilogueBegin, - - /// "The DW_LNS_set_isa opcode takes a single unsigned LEB128 operand and - /// stores that value in the isa register of the state machine." - SetIsa(u64), - - /// An unknown standard opcode with zero operands. - UnknownStandard0(constants::DwLns), - - /// An unknown standard opcode with one operand. - UnknownStandard1(constants::DwLns, u64), - - /// An unknown standard opcode with multiple operands. - UnknownStandardN(constants::DwLns, R), - - /// > [`LineInstruction::EndSequence`] sets the end_sequence register of the state - /// > machine to “true” and appends a row to the matrix using the current - /// > values of the state-machine registers. Then it resets the registers to - /// > the initial values specified above (see Section 6.2.2). Every line - /// > number program sequence must end with a DW_LNE_end_sequence instruction - /// > which creates a row whose address is that of the byte after the last - /// > target machine instruction of the sequence. - EndSequence, - - /// > The DW_LNE_set_address opcode takes a single relocatable address as an - /// > operand. The size of the operand is the size of an address on the target - /// > machine. It sets the address register to the value given by the - /// > relocatable address and sets the op_index register to 0. - /// > - /// > All of the other line number program opcodes that affect the address - /// > register add a delta to it. This instruction stores a relocatable value - /// > into it instead. - SetAddress(u64), - - /// Defines a new source file in the line number program and appends it to - /// the line number program header's list of source files. - DefineFile(FileEntry<R, Offset>), - - /// "The DW_LNE_set_discriminator opcode takes a single parameter, an - /// unsigned LEB128 integer. It sets the discriminator register to the new - /// value." - SetDiscriminator(u64), - - /// An unknown extended opcode and the slice of its unparsed operands. - UnknownExtended(constants::DwLne, R), -} - -impl<R, Offset> LineInstruction<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - fn parse<'header>( - header: &'header LineProgramHeader<R>, - input: &mut R, - ) -> Result<LineInstruction<R>> - where - R: 'header, - { - let opcode = input.read_u8()?; - if opcode == 0 { - let length = input.read_uleb128().and_then(R::Offset::from_u64)?; - let mut instr_rest = input.split(length)?; - let opcode = instr_rest.read_u8()?; - - match constants::DwLne(opcode) { - constants::DW_LNE_end_sequence => Ok(LineInstruction::EndSequence), - - constants::DW_LNE_set_address => { - let address = instr_rest.read_address(header.address_size())?; - Ok(LineInstruction::SetAddress(address)) - } - - constants::DW_LNE_define_file => { - if header.version() <= 4 { - let path_name = instr_rest.read_null_terminated_slice()?; - let entry = FileEntry::parse(&mut instr_rest, path_name)?; - Ok(LineInstruction::DefineFile(entry)) - } else { - Ok(LineInstruction::UnknownExtended( - constants::DW_LNE_define_file, - instr_rest, - )) - } - } - - constants::DW_LNE_set_discriminator => { - let discriminator = instr_rest.read_uleb128()?; - Ok(LineInstruction::SetDiscriminator(discriminator)) - } - - otherwise => Ok(LineInstruction::UnknownExtended(otherwise, instr_rest)), - } - } else if opcode >= header.opcode_base { - Ok(LineInstruction::Special(opcode)) - } else { - match constants::DwLns(opcode) { - constants::DW_LNS_copy => Ok(LineInstruction::Copy), - - constants::DW_LNS_advance_pc => { - let advance = input.read_uleb128()?; - Ok(LineInstruction::AdvancePc(advance)) - } - - constants::DW_LNS_advance_line => { - let increment = input.read_sleb128()?; - Ok(LineInstruction::AdvanceLine(increment)) - } - - constants::DW_LNS_set_file => { - let file = input.read_uleb128()?; - Ok(LineInstruction::SetFile(file)) - } - - constants::DW_LNS_set_column => { - let column = input.read_uleb128()?; - Ok(LineInstruction::SetColumn(column)) - } - - constants::DW_LNS_negate_stmt => Ok(LineInstruction::NegateStatement), - - constants::DW_LNS_set_basic_block => Ok(LineInstruction::SetBasicBlock), - - constants::DW_LNS_const_add_pc => Ok(LineInstruction::ConstAddPc), - - constants::DW_LNS_fixed_advance_pc => { - let advance = input.read_u16()?; - Ok(LineInstruction::FixedAddPc(advance)) - } - - constants::DW_LNS_set_prologue_end => Ok(LineInstruction::SetPrologueEnd), - - constants::DW_LNS_set_epilogue_begin => Ok(LineInstruction::SetEpilogueBegin), - - constants::DW_LNS_set_isa => { - let isa = input.read_uleb128()?; - Ok(LineInstruction::SetIsa(isa)) - } - - otherwise => { - let mut opcode_lengths = header.standard_opcode_lengths().clone(); - opcode_lengths.skip(R::Offset::from_u8(opcode - 1))?; - let num_args = opcode_lengths.read_u8()? as usize; - match num_args { - 0 => Ok(LineInstruction::UnknownStandard0(otherwise)), - 1 => { - let arg = input.read_uleb128()?; - Ok(LineInstruction::UnknownStandard1(otherwise, arg)) - } - _ => { - let mut args = input.clone(); - for _ in 0..num_args { - input.read_uleb128()?; - } - let len = input.offset_from(&args); - args.truncate(len)?; - Ok(LineInstruction::UnknownStandardN(otherwise, args)) - } - } - } - } - } - } -} - -impl<R, Offset> fmt::Display for LineInstruction<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { - match *self { - LineInstruction::Special(opcode) => write!(f, "Special opcode {}", opcode), - LineInstruction::Copy => write!(f, "{}", constants::DW_LNS_copy), - LineInstruction::AdvancePc(advance) => { - write!(f, "{} by {}", constants::DW_LNS_advance_pc, advance) - } - LineInstruction::AdvanceLine(increment) => { - write!(f, "{} by {}", constants::DW_LNS_advance_line, increment) - } - LineInstruction::SetFile(file) => { - write!(f, "{} to {}", constants::DW_LNS_set_file, file) - } - LineInstruction::SetColumn(column) => { - write!(f, "{} to {}", constants::DW_LNS_set_column, column) - } - LineInstruction::NegateStatement => write!(f, "{}", constants::DW_LNS_negate_stmt), - LineInstruction::SetBasicBlock => write!(f, "{}", constants::DW_LNS_set_basic_block), - LineInstruction::ConstAddPc => write!(f, "{}", constants::DW_LNS_const_add_pc), - LineInstruction::FixedAddPc(advance) => { - write!(f, "{} by {}", constants::DW_LNS_fixed_advance_pc, advance) - } - LineInstruction::SetPrologueEnd => write!(f, "{}", constants::DW_LNS_set_prologue_end), - LineInstruction::SetEpilogueBegin => { - write!(f, "{}", constants::DW_LNS_set_epilogue_begin) - } - LineInstruction::SetIsa(isa) => write!(f, "{} to {}", constants::DW_LNS_set_isa, isa), - LineInstruction::UnknownStandard0(opcode) => write!(f, "Unknown {}", opcode), - LineInstruction::UnknownStandard1(opcode, arg) => { - write!(f, "Unknown {} with operand {}", opcode, arg) - } - LineInstruction::UnknownStandardN(opcode, ref args) => { - write!(f, "Unknown {} with operands {:?}", opcode, args) - } - LineInstruction::EndSequence => write!(f, "{}", constants::DW_LNE_end_sequence), - LineInstruction::SetAddress(address) => { - write!(f, "{} to {}", constants::DW_LNE_set_address, address) - } - LineInstruction::DefineFile(_) => write!(f, "{}", constants::DW_LNE_define_file), - LineInstruction::SetDiscriminator(discr) => { - write!(f, "{} to {}", constants::DW_LNE_set_discriminator, discr) - } - LineInstruction::UnknownExtended(opcode, _) => write!(f, "Unknown {}", opcode), - } - } -} - -/// Deprecated. `OpcodesIter` has been renamed to `LineInstructions`. -#[deprecated(note = "OpcodesIter has been renamed to LineInstructions, use that instead.")] -pub type OpcodesIter<R> = LineInstructions<R>; - -/// An iterator yielding parsed instructions. -/// -/// See -/// [`LineProgramHeader::instructions`](./struct.LineProgramHeader.html#method.instructions) -/// for more details. -#[derive(Clone, Debug)] -pub struct LineInstructions<R: Reader> { - input: R, -} - -impl<R: Reader> LineInstructions<R> { - fn remove_trailing(&self, other: &LineInstructions<R>) -> Result<LineInstructions<R>> { - let offset = other.input.offset_from(&self.input); - let mut input = self.input.clone(); - input.truncate(offset)?; - Ok(LineInstructions { input }) - } -} - -impl<R: Reader> LineInstructions<R> { - /// Advance the iterator and return the next instruction. - /// - /// Returns the newly parsed instruction as `Ok(Some(instruction))`. Returns - /// `Ok(None)` when iteration is complete and all instructions have already been - /// parsed and yielded. If an error occurs while parsing the next attribute, - /// then this error is returned as `Err(e)`, and all subsequent calls return - /// `Ok(None)`. - /// - /// Unfortunately, the `header` parameter means that this cannot be a - /// `FallibleIterator`. - #[inline(always)] - pub fn next_instruction( - &mut self, - header: &LineProgramHeader<R>, - ) -> Result<Option<LineInstruction<R>>> { - if self.input.is_empty() { - return Ok(None); - } - - match LineInstruction::parse(header, &mut self.input) { - Ok(instruction) => Ok(Some(instruction)), - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -/// Deprecated. `LineNumberRow` has been renamed to `LineRow`. -#[deprecated(note = "LineNumberRow has been renamed to LineRow, use that instead.")] -pub type LineNumberRow = LineRow; - -/// A row in the line number program's resulting matrix. -/// -/// Each row is a copy of the registers of the state machine, as defined in section 6.2.2. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct LineRow { - tombstone: bool, - address: Wrapping<u64>, - op_index: Wrapping<u64>, - file: u64, - line: Wrapping<u64>, - column: u64, - is_stmt: bool, - basic_block: bool, - end_sequence: bool, - prologue_end: bool, - epilogue_begin: bool, - isa: u64, - discriminator: u64, -} - -impl LineRow { - /// Create a line number row in the initial state for the given program. - pub fn new<R: Reader>(header: &LineProgramHeader<R>) -> Self { - LineRow { - // "At the beginning of each sequence within a line number program, the - // state of the registers is:" -- Section 6.2.2 - tombstone: false, - address: Wrapping(0), - op_index: Wrapping(0), - file: 1, - line: Wrapping(1), - column: 0, - // "determined by default_is_stmt in the line number program header" - is_stmt: header.line_encoding.default_is_stmt, - basic_block: false, - end_sequence: false, - prologue_end: false, - epilogue_begin: false, - // "The isa value 0 specifies that the instruction set is the - // architecturally determined default instruction set. This may be fixed - // by the ABI, or it may be specified by other means, for example, by - // the object file description." - isa: 0, - discriminator: 0, - } - } - - /// "The program-counter value corresponding to a machine instruction - /// generated by the compiler." - #[inline] - pub fn address(&self) -> u64 { - self.address.0 - } - - /// > An unsigned integer representing the index of an operation within a VLIW - /// > instruction. The index of the first operation is 0. For non-VLIW - /// > architectures, this register will always be 0. - /// > - /// > The address and op_index registers, taken together, form an operation - /// > pointer that can reference any individual operation with the - /// > instruction stream. - #[inline] - pub fn op_index(&self) -> u64 { - self.op_index.0 - } - - /// "An unsigned integer indicating the identity of the source file - /// corresponding to a machine instruction." - #[inline] - pub fn file_index(&self) -> u64 { - self.file - } - - /// The source file corresponding to the current machine instruction. - #[inline] - pub fn file<'header, R: Reader>( - &self, - header: &'header LineProgramHeader<R>, - ) -> Option<&'header FileEntry<R>> { - header.file(self.file) - } - - /// "An unsigned integer indicating a source line number. Lines are numbered - /// beginning at 1. The compiler may emit the value 0 in cases where an - /// instruction cannot be attributed to any source line." - /// Line number values of 0 are represented as `None`. - #[inline] - pub fn line(&self) -> Option<NonZeroU64> { - NonZeroU64::new(self.line.0) - } - - /// "An unsigned integer indicating a column number within a source - /// line. Columns are numbered beginning at 1. The value 0 is reserved to - /// indicate that a statement begins at the “left edge” of the line." - #[inline] - pub fn column(&self) -> ColumnType { - NonZeroU64::new(self.column) - .map(ColumnType::Column) - .unwrap_or(ColumnType::LeftEdge) - } - - /// "A boolean indicating that the current instruction is a recommended - /// breakpoint location. A recommended breakpoint location is intended to - /// “represent” a line, a statement and/or a semantically distinct subpart - /// of a statement." - #[inline] - pub fn is_stmt(&self) -> bool { - self.is_stmt - } - - /// "A boolean indicating that the current instruction is the beginning of a - /// basic block." - #[inline] - pub fn basic_block(&self) -> bool { - self.basic_block - } - - /// "A boolean indicating that the current address is that of the first byte - /// after the end of a sequence of target machine instructions. end_sequence - /// terminates a sequence of lines; therefore other information in the same - /// row is not meaningful." - #[inline] - pub fn end_sequence(&self) -> bool { - self.end_sequence - } - - /// "A boolean indicating that the current address is one (of possibly many) - /// where execution should be suspended for an entry breakpoint of a - /// function." - #[inline] - pub fn prologue_end(&self) -> bool { - self.prologue_end - } - - /// "A boolean indicating that the current address is one (of possibly many) - /// where execution should be suspended for an exit breakpoint of a - /// function." - #[inline] - pub fn epilogue_begin(&self) -> bool { - self.epilogue_begin - } - - /// Tag for the current instruction set architecture. - /// - /// > An unsigned integer whose value encodes the applicable instruction set - /// > architecture for the current instruction. - /// > - /// > The encoding of instruction sets should be shared by all users of a - /// > given architecture. It is recommended that this encoding be defined by - /// > the ABI authoring committee for each architecture. - #[inline] - pub fn isa(&self) -> u64 { - self.isa - } - - /// "An unsigned integer identifying the block to which the current - /// instruction belongs. Discriminator values are assigned arbitrarily by - /// the DWARF producer and serve to distinguish among multiple blocks that - /// may all be associated with the same source file, line, and column. Where - /// only one block exists for a given source position, the discriminator - /// value should be zero." - #[inline] - pub fn discriminator(&self) -> u64 { - self.discriminator - } - - /// Execute the given instruction, and return true if a new row in the - /// line number matrix needs to be generated. - /// - /// Unknown opcodes are treated as no-ops. - #[inline] - pub fn execute<R, Program>( - &mut self, - instruction: LineInstruction<R>, - program: &mut Program, - ) -> bool - where - Program: LineProgram<R>, - R: Reader, - { - match instruction { - LineInstruction::Special(opcode) => { - self.exec_special_opcode(opcode, program.header()); - true - } - - LineInstruction::Copy => true, - - LineInstruction::AdvancePc(operation_advance) => { - self.apply_operation_advance(operation_advance, program.header()); - false - } - - LineInstruction::AdvanceLine(line_increment) => { - self.apply_line_advance(line_increment); - false - } - - LineInstruction::SetFile(file) => { - self.file = file; - false - } - - LineInstruction::SetColumn(column) => { - self.column = column; - false - } - - LineInstruction::NegateStatement => { - self.is_stmt = !self.is_stmt; - false - } - - LineInstruction::SetBasicBlock => { - self.basic_block = true; - false - } - - LineInstruction::ConstAddPc => { - let adjusted = self.adjust_opcode(255, program.header()); - let operation_advance = adjusted / program.header().line_encoding.line_range; - self.apply_operation_advance(u64::from(operation_advance), program.header()); - false - } - - LineInstruction::FixedAddPc(operand) => { - self.address += Wrapping(u64::from(operand)); - self.op_index.0 = 0; - false - } - - LineInstruction::SetPrologueEnd => { - self.prologue_end = true; - false - } - - LineInstruction::SetEpilogueBegin => { - self.epilogue_begin = true; - false - } - - LineInstruction::SetIsa(isa) => { - self.isa = isa; - false - } - - LineInstruction::EndSequence => { - self.end_sequence = true; - true - } - - LineInstruction::SetAddress(address) => { - let tombstone_address = !0 >> (64 - program.header().encoding.address_size * 8); - self.tombstone = address == tombstone_address; - self.address.0 = address; - self.op_index.0 = 0; - false - } - - LineInstruction::DefineFile(entry) => { - program.add_file(entry); - false - } - - LineInstruction::SetDiscriminator(discriminator) => { - self.discriminator = discriminator; - false - } - - // Compatibility with future opcodes. - LineInstruction::UnknownStandard0(_) - | LineInstruction::UnknownStandard1(_, _) - | LineInstruction::UnknownStandardN(_, _) - | LineInstruction::UnknownExtended(_, _) => false, - } - } - - /// Perform any reset that was required after copying the previous row. - #[inline] - pub fn reset<R: Reader>(&mut self, header: &LineProgramHeader<R>) { - if self.end_sequence { - // Previous instruction was EndSequence, so reset everything - // as specified in Section 6.2.5.3. - *self = Self::new(header); - } else { - // Previous instruction was one of: - // - Special - specified in Section 6.2.5.1, steps 4-7 - // - Copy - specified in Section 6.2.5.2 - // The reset behaviour is the same in both cases. - self.discriminator = 0; - self.basic_block = false; - self.prologue_end = false; - self.epilogue_begin = false; - } - } - - /// Step 1 of section 6.2.5.1 - fn apply_line_advance(&mut self, line_increment: i64) { - if line_increment < 0 { - let decrement = -line_increment as u64; - if decrement <= self.line.0 { - self.line.0 -= decrement; - } else { - self.line.0 = 0; - } - } else { - self.line += Wrapping(line_increment as u64); - } - } - - /// Step 2 of section 6.2.5.1 - fn apply_operation_advance<R: Reader>( - &mut self, - operation_advance: u64, - header: &LineProgramHeader<R>, - ) { - let operation_advance = Wrapping(operation_advance); - - let minimum_instruction_length = u64::from(header.line_encoding.minimum_instruction_length); - let minimum_instruction_length = Wrapping(minimum_instruction_length); - - let maximum_operations_per_instruction = - u64::from(header.line_encoding.maximum_operations_per_instruction); - let maximum_operations_per_instruction = Wrapping(maximum_operations_per_instruction); - - if maximum_operations_per_instruction.0 == 1 { - self.address += minimum_instruction_length * operation_advance; - self.op_index.0 = 0; - } else { - let op_index_with_advance = self.op_index + operation_advance; - self.address += minimum_instruction_length - * (op_index_with_advance / maximum_operations_per_instruction); - self.op_index = op_index_with_advance % maximum_operations_per_instruction; - } - } - - #[inline] - fn adjust_opcode<R: Reader>(&self, opcode: u8, header: &LineProgramHeader<R>) -> u8 { - opcode - header.opcode_base - } - - /// Section 6.2.5.1 - fn exec_special_opcode<R: Reader>(&mut self, opcode: u8, header: &LineProgramHeader<R>) { - let adjusted_opcode = self.adjust_opcode(opcode, header); - - let line_range = header.line_encoding.line_range; - let line_advance = adjusted_opcode % line_range; - let operation_advance = adjusted_opcode / line_range; - - // Step 1 - let line_base = i64::from(header.line_encoding.line_base); - self.apply_line_advance(line_base + i64::from(line_advance)); - - // Step 2 - self.apply_operation_advance(u64::from(operation_advance), header); - } -} - -/// The type of column that a row is referring to. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum ColumnType { - /// The `LeftEdge` means that the statement begins at the start of the new - /// line. - LeftEdge, - /// A column number, whose range begins at 1. - Column(NonZeroU64), -} - -/// Deprecated. `LineNumberSequence` has been renamed to `LineSequence`. -#[deprecated(note = "LineNumberSequence has been renamed to LineSequence, use that instead.")] -pub type LineNumberSequence<R> = LineSequence<R>; - -/// A sequence within a line number program. A sequence, as defined in section -/// 6.2.5 of the standard, is a linear subset of a line number program within -/// which addresses are monotonically increasing. -#[derive(Clone, Debug)] -pub struct LineSequence<R: Reader> { - /// The first address that is covered by this sequence within the line number - /// program. - pub start: u64, - /// The first address that is *not* covered by this sequence within the line - /// number program. - pub end: u64, - instructions: LineInstructions<R>, -} - -/// Deprecated. `LineNumberProgramHeader` has been renamed to `LineProgramHeader`. -#[deprecated( - note = "LineNumberProgramHeader has been renamed to LineProgramHeader, use that instead." -)] -pub type LineNumberProgramHeader<R, Offset> = LineProgramHeader<R, Offset>; - -/// A header for a line number program in the `.debug_line` section, as defined -/// in section 6.2.4 of the standard. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct LineProgramHeader<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - encoding: Encoding, - offset: DebugLineOffset<Offset>, - unit_length: Offset, - - header_length: Offset, - - line_encoding: LineEncoding, - - /// "The number assigned to the first special opcode." - opcode_base: u8, - - /// "This array specifies the number of LEB128 operands for each of the - /// standard opcodes. The first element of the array corresponds to the - /// opcode whose value is 1, and the last element corresponds to the opcode - /// whose value is `opcode_base - 1`." - standard_opcode_lengths: R, - - /// "A sequence of directory entry format descriptions." - directory_entry_format: Vec<FileEntryFormat>, - - /// > Entries in this sequence describe each path that was searched for - /// > included source files in this compilation. (The paths include those - /// > directories specified explicitly by the user for the compiler to search - /// > and those the compiler searches without explicit direction.) Each path - /// > entry is either a full path name or is relative to the current directory - /// > of the compilation. - /// > - /// > The last entry is followed by a single null byte. - include_directories: Vec<AttributeValue<R, Offset>>, - - /// "A sequence of file entry format descriptions." - file_name_entry_format: Vec<FileEntryFormat>, - - /// "Entries in this sequence describe source files that contribute to the - /// line number information for this compilation unit or is used in other - /// contexts." - file_names: Vec<FileEntry<R, Offset>>, - - /// The encoded line program instructions. - program_buf: R, - - /// The current directory of the compilation. - comp_dir: Option<R>, - - /// The primary source file. - comp_file: Option<FileEntry<R, Offset>>, -} - -impl<R, Offset> LineProgramHeader<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Return the offset of the line number program header in the `.debug_line` section. - pub fn offset(&self) -> DebugLineOffset<R::Offset> { - self.offset - } - - /// Return the length of the line number program and header, not including - /// the length of the encoded length itself. - pub fn unit_length(&self) -> R::Offset { - self.unit_length - } - - /// Return the encoding parameters for this header's line program. - pub fn encoding(&self) -> Encoding { - self.encoding - } - - /// Get the version of this header's line program. - pub fn version(&self) -> u16 { - self.encoding.version - } - - /// Get the length of the encoded line number program header, not including - /// the length of the encoded length itself. - pub fn header_length(&self) -> R::Offset { - self.header_length - } - - /// Get the size in bytes of a target machine address. - pub fn address_size(&self) -> u8 { - self.encoding.address_size - } - - /// Whether this line program is encoded in 64- or 32-bit DWARF. - pub fn format(&self) -> Format { - self.encoding.format - } - - /// Get the line encoding parameters for this header's line program. - pub fn line_encoding(&self) -> LineEncoding { - self.line_encoding - } - - /// Get the minimum instruction length any instruction in this header's line - /// program may have. - pub fn minimum_instruction_length(&self) -> u8 { - self.line_encoding.minimum_instruction_length - } - - /// Get the maximum number of operations each instruction in this header's - /// line program may have. - pub fn maximum_operations_per_instruction(&self) -> u8 { - self.line_encoding.maximum_operations_per_instruction - } - - /// Get the default value of the `is_stmt` register for this header's line - /// program. - pub fn default_is_stmt(&self) -> bool { - self.line_encoding.default_is_stmt - } - - /// Get the line base for this header's line program. - pub fn line_base(&self) -> i8 { - self.line_encoding.line_base - } - - /// Get the line range for this header's line program. - pub fn line_range(&self) -> u8 { - self.line_encoding.line_range - } - - /// Get opcode base for this header's line program. - pub fn opcode_base(&self) -> u8 { - self.opcode_base - } - - /// An array of `u8` that specifies the number of LEB128 operands for - /// each of the standard opcodes. - pub fn standard_opcode_lengths(&self) -> &R { - &self.standard_opcode_lengths - } - - /// Get the format of a directory entry. - pub fn directory_entry_format(&self) -> &[FileEntryFormat] { - &self.directory_entry_format[..] - } - - /// Get the set of include directories for this header's line program. - /// - /// For DWARF version <= 4, the compilation's current directory is not included - /// in the return value, but is implicitly considered to be in the set per spec. - pub fn include_directories(&self) -> &[AttributeValue<R, Offset>] { - &self.include_directories[..] - } - - /// The include directory with the given directory index. - /// - /// A directory index of 0 corresponds to the compilation unit directory. - pub fn directory(&self, directory: u64) -> Option<AttributeValue<R, Offset>> { - if self.encoding.version <= 4 { - if directory == 0 { - self.comp_dir.clone().map(AttributeValue::String) - } else { - let directory = directory as usize - 1; - self.include_directories.get(directory).cloned() - } - } else { - self.include_directories.get(directory as usize).cloned() - } - } - - /// Get the format of a file name entry. - pub fn file_name_entry_format(&self) -> &[FileEntryFormat] { - &self.file_name_entry_format[..] - } - - /// Return true if the file entries may have valid timestamps. - /// - /// Only returns false if we definitely know that all timestamp fields - /// are invalid. - pub fn file_has_timestamp(&self) -> bool { - self.encoding.version <= 4 - || self - .file_name_entry_format - .iter() - .any(|x| x.content_type == constants::DW_LNCT_timestamp) - } - - /// Return true if the file entries may have valid sizes. - /// - /// Only returns false if we definitely know that all size fields - /// are invalid. - pub fn file_has_size(&self) -> bool { - self.encoding.version <= 4 - || self - .file_name_entry_format - .iter() - .any(|x| x.content_type == constants::DW_LNCT_size) - } - - /// Return true if the file name entry format contains an MD5 field. - pub fn file_has_md5(&self) -> bool { - self.file_name_entry_format - .iter() - .any(|x| x.content_type == constants::DW_LNCT_MD5) - } - - /// Get the list of source files that appear in this header's line program. - pub fn file_names(&self) -> &[FileEntry<R, Offset>] { - &self.file_names[..] - } - - /// The source file with the given file index. - /// - /// A file index of 0 corresponds to the compilation unit file. - /// Note that a file index of 0 is invalid for DWARF version <= 4, - /// but we support it anyway. - pub fn file(&self, file: u64) -> Option<&FileEntry<R, Offset>> { - if self.encoding.version <= 4 { - if file == 0 { - self.comp_file.as_ref() - } else { - let file = file as usize - 1; - self.file_names.get(file) - } - } else { - self.file_names.get(file as usize) - } - } - - /// Get the raw, un-parsed `EndianSlice` containing this header's line number - /// program. - /// - /// ``` - /// # fn foo() { - /// use gimli::{LineProgramHeader, EndianSlice, NativeEndian}; - /// - /// fn get_line_number_program_header<'a>() -> LineProgramHeader<EndianSlice<'a, NativeEndian>> { - /// // Get a line number program header from some offset in a - /// // `.debug_line` section... - /// # unimplemented!() - /// } - /// - /// let header = get_line_number_program_header(); - /// let raw_program = header.raw_program_buf(); - /// println!("The length of the raw program in bytes is {}", raw_program.len()); - /// # } - /// ``` - pub fn raw_program_buf(&self) -> R { - self.program_buf.clone() - } - - /// Iterate over the instructions in this header's line number program, parsing - /// them as we go. - pub fn instructions(&self) -> LineInstructions<R> { - LineInstructions { - input: self.program_buf.clone(), - } - } - - fn parse( - input: &mut R, - offset: DebugLineOffset<Offset>, - mut address_size: u8, - mut comp_dir: Option<R>, - comp_name: Option<R>, - ) -> Result<LineProgramHeader<R, Offset>> { - let (unit_length, format) = input.read_initial_length()?; - let rest = &mut input.split(unit_length)?; - - let version = rest.read_u16()?; - if version < 2 || version > 5 { - return Err(Error::UnknownVersion(u64::from(version))); - } - - if version >= 5 { - address_size = rest.read_u8()?; - let segment_selector_size = rest.read_u8()?; - if segment_selector_size != 0 { - return Err(Error::UnsupportedSegmentSize); - } - } - - let encoding = Encoding { - format, - version, - address_size, - }; - - let header_length = rest.read_length(format)?; - - let mut program_buf = rest.clone(); - program_buf.skip(header_length)?; - rest.truncate(header_length)?; - - let minimum_instruction_length = rest.read_u8()?; - if minimum_instruction_length == 0 { - return Err(Error::MinimumInstructionLengthZero); - } - - // This field did not exist before DWARF 4, but is specified to be 1 for - // non-VLIW architectures, which makes it a no-op. - let maximum_operations_per_instruction = if version >= 4 { rest.read_u8()? } else { 1 }; - if maximum_operations_per_instruction == 0 { - return Err(Error::MaximumOperationsPerInstructionZero); - } - - let default_is_stmt = rest.read_u8()? != 0; - let line_base = rest.read_i8()?; - let line_range = rest.read_u8()?; - if line_range == 0 { - return Err(Error::LineRangeZero); - } - let line_encoding = LineEncoding { - minimum_instruction_length, - maximum_operations_per_instruction, - default_is_stmt, - line_base, - line_range, - }; - - let opcode_base = rest.read_u8()?; - if opcode_base == 0 { - return Err(Error::OpcodeBaseZero); - } - - let standard_opcode_count = R::Offset::from_u8(opcode_base - 1); - let standard_opcode_lengths = rest.split(standard_opcode_count)?; - - let directory_entry_format; - let mut include_directories = Vec::new(); - if version <= 4 { - directory_entry_format = Vec::new(); - loop { - let directory = rest.read_null_terminated_slice()?; - if directory.is_empty() { - break; - } - include_directories.push(AttributeValue::String(directory)); - } - } else { - comp_dir = None; - directory_entry_format = FileEntryFormat::parse(rest)?; - let count = rest.read_uleb128()?; - for _ in 0..count { - include_directories.push(parse_directory_v5( - rest, - encoding, - &directory_entry_format, - )?); - } - } - - let comp_file; - let file_name_entry_format; - let mut file_names = Vec::new(); - if version <= 4 { - comp_file = comp_name.map(|name| FileEntry { - path_name: AttributeValue::String(name), - directory_index: 0, - timestamp: 0, - size: 0, - md5: [0; 16], - }); - - file_name_entry_format = Vec::new(); - loop { - let path_name = rest.read_null_terminated_slice()?; - if path_name.is_empty() { - break; - } - file_names.push(FileEntry::parse(rest, path_name)?); - } - } else { - comp_file = None; - file_name_entry_format = FileEntryFormat::parse(rest)?; - let count = rest.read_uleb128()?; - for _ in 0..count { - file_names.push(parse_file_v5(rest, encoding, &file_name_entry_format)?); - } - } - - let header = LineProgramHeader { - encoding, - offset, - unit_length, - header_length, - line_encoding, - opcode_base, - standard_opcode_lengths, - directory_entry_format, - include_directories, - file_name_entry_format, - file_names, - program_buf, - comp_dir, - comp_file, - }; - Ok(header) - } -} - -/// Deprecated. `IncompleteLineNumberProgram` has been renamed to `IncompleteLineProgram`. -#[deprecated( - note = "IncompleteLineNumberProgram has been renamed to IncompleteLineProgram, use that instead." -)] -pub type IncompleteLineNumberProgram<R, Offset> = IncompleteLineProgram<R, Offset>; - -/// A line number program that has not been run to completion. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct IncompleteLineProgram<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - header: LineProgramHeader<R, Offset>, -} - -impl<R, Offset> IncompleteLineProgram<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Retrieve the `LineProgramHeader` for this program. - pub fn header(&self) -> &LineProgramHeader<R, Offset> { - &self.header - } - - /// Construct a new `LineRows` for executing this program to iterate - /// over rows in the line information matrix. - pub fn rows(self) -> OneShotLineRows<R, Offset> { - OneShotLineRows::new(self) - } - - /// Execute the line number program, completing the `IncompleteLineProgram` - /// into a `CompleteLineProgram` and producing an array of sequences within - /// the line number program that can later be used with - /// `CompleteLineProgram::resume_from`. - /// - /// ``` - /// # fn foo() { - /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian}; - /// - /// fn get_line_number_program<'a>() -> IncompleteLineProgram<EndianSlice<'a, NativeEndian>> { - /// // Get a line number program from some offset in a - /// // `.debug_line` section... - /// # unimplemented!() - /// } - /// - /// let program = get_line_number_program(); - /// let (program, sequences) = program.sequences().unwrap(); - /// println!("There are {} sequences in this line number program", sequences.len()); - /// # } - /// ``` - #[allow(clippy::type_complexity)] - pub fn sequences(self) -> Result<(CompleteLineProgram<R, Offset>, Vec<LineSequence<R>>)> { - let mut sequences = Vec::new(); - let mut rows = self.rows(); - let mut instructions = rows.instructions.clone(); - let mut sequence_start_addr = None; - loop { - let sequence_end_addr; - if rows.next_row()?.is_none() { - break; - } - - let row = &rows.row; - if row.end_sequence() { - sequence_end_addr = row.address(); - } else if sequence_start_addr.is_none() { - sequence_start_addr = Some(row.address()); - continue; - } else { - continue; - } - - // We just finished a sequence. - sequences.push(LineSequence { - // In theory one could have multiple DW_LNE_end_sequence instructions - // in a row. - start: sequence_start_addr.unwrap_or(0), - end: sequence_end_addr, - instructions: instructions.remove_trailing(&rows.instructions)?, - }); - sequence_start_addr = None; - instructions = rows.instructions.clone(); - } - - let program = CompleteLineProgram { - header: rows.program.header, - }; - Ok((program, sequences)) - } -} - -/// Deprecated. `CompleteLineNumberProgram` has been renamed to `CompleteLineProgram`. -#[deprecated( - note = "CompleteLineNumberProgram has been renamed to CompleteLineProgram, use that instead." -)] -pub type CompleteLineNumberProgram<R, Offset> = CompleteLineProgram<R, Offset>; - -/// A line number program that has previously been run to completion. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CompleteLineProgram<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - header: LineProgramHeader<R, Offset>, -} - -impl<R, Offset> CompleteLineProgram<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Retrieve the `LineProgramHeader` for this program. - pub fn header(&self) -> &LineProgramHeader<R, Offset> { - &self.header - } - - /// Construct a new `LineRows` for executing the subset of the line - /// number program identified by 'sequence' and generating the line information - /// matrix. - /// - /// ``` - /// # fn foo() { - /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian}; - /// - /// fn get_line_number_program<'a>() -> IncompleteLineProgram<EndianSlice<'a, NativeEndian>> { - /// // Get a line number program from some offset in a - /// // `.debug_line` section... - /// # unimplemented!() - /// } - /// - /// let program = get_line_number_program(); - /// let (program, sequences) = program.sequences().unwrap(); - /// for sequence in &sequences { - /// let mut sm = program.resume_from(sequence); - /// } - /// # } - /// ``` - pub fn resume_from<'program>( - &'program self, - sequence: &LineSequence<R>, - ) -> ResumedLineRows<'program, R, Offset> { - ResumedLineRows::resume(self, sequence) - } -} - -/// An entry in the `LineProgramHeader`'s `file_names` set. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct FileEntry<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - path_name: AttributeValue<R, Offset>, - directory_index: u64, - timestamp: u64, - size: u64, - md5: [u8; 16], -} - -impl<R, Offset> FileEntry<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - // version 2-4 - fn parse(input: &mut R, path_name: R) -> Result<FileEntry<R, Offset>> { - let directory_index = input.read_uleb128()?; - let timestamp = input.read_uleb128()?; - let size = input.read_uleb128()?; - - let entry = FileEntry { - path_name: AttributeValue::String(path_name), - directory_index, - timestamp, - size, - md5: [0; 16], - }; - - Ok(entry) - } - - /// > A slice containing the full or relative path name of - /// > a source file. If the entry contains a file name or a relative path - /// > name, the file is located relative to either the compilation directory - /// > (as specified by the DW_AT_comp_dir attribute given in the compilation - /// > unit) or one of the directories in the include_directories section. - pub fn path_name(&self) -> AttributeValue<R, Offset> { - self.path_name.clone() - } - - /// > An unsigned LEB128 number representing the directory index of the - /// > directory in which the file was found. - /// > - /// > ... - /// > - /// > The directory index represents an entry in the include_directories - /// > section of the line number program header. The index is 0 if the file - /// > was found in the current directory of the compilation, 1 if it was found - /// > in the first directory in the include_directories section, and so - /// > on. The directory index is ignored for file names that represent full - /// > path names. - pub fn directory_index(&self) -> u64 { - self.directory_index - } - - /// Get this file's directory. - /// - /// A directory index of 0 corresponds to the compilation unit directory. - pub fn directory(&self, header: &LineProgramHeader<R>) -> Option<AttributeValue<R, Offset>> { - header.directory(self.directory_index) - } - - /// The implementation-defined time of last modification of the file, - /// or 0 if not available. - pub fn timestamp(&self) -> u64 { - self.timestamp - } - - /// "An unsigned LEB128 number representing the time of last modification of - /// the file, or 0 if not available." - // Terminology changed in DWARF version 5. - #[doc(hidden)] - pub fn last_modification(&self) -> u64 { - self.timestamp - } - - /// The size of the file in bytes, or 0 if not available. - pub fn size(&self) -> u64 { - self.size - } - - /// "An unsigned LEB128 number representing the length in bytes of the file, - /// or 0 if not available." - // Terminology changed in DWARF version 5. - #[doc(hidden)] - pub fn length(&self) -> u64 { - self.size - } - - /// A 16-byte MD5 digest of the file contents. - /// - /// Only valid if `LineProgramHeader::file_has_md5` returns `true`. - pub fn md5(&self) -> &[u8; 16] { - &self.md5 - } -} - -/// The format of a component of an include directory or file name entry. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct FileEntryFormat { - /// The type of information that is represented by the component. - pub content_type: constants::DwLnct, - - /// The encoding form of the component value. - pub form: constants::DwForm, -} - -impl FileEntryFormat { - fn parse<R: Reader>(input: &mut R) -> Result<Vec<FileEntryFormat>> { - let format_count = input.read_u8()? as usize; - let mut format = Vec::with_capacity(format_count); - let mut path_count = 0; - for _ in 0..format_count { - let content_type = input.read_uleb128()?; - let content_type = if content_type > u64::from(u16::max_value()) { - constants::DwLnct(u16::max_value()) - } else { - constants::DwLnct(content_type as u16) - }; - if content_type == constants::DW_LNCT_path { - path_count += 1; - } - - let form = constants::DwForm(input.read_uleb128_u16()?); - - format.push(FileEntryFormat { content_type, form }); - } - if path_count != 1 { - return Err(Error::MissingFileEntryFormatPath); - } - Ok(format) - } -} - -fn parse_directory_v5<R: Reader>( - input: &mut R, - encoding: Encoding, - formats: &[FileEntryFormat], -) -> Result<AttributeValue<R>> { - let mut path_name = None; - - for format in formats { - let value = parse_attribute(input, encoding, format.form)?; - if format.content_type == constants::DW_LNCT_path { - path_name = Some(value); - } - } - - Ok(path_name.unwrap()) -} - -fn parse_file_v5<R: Reader>( - input: &mut R, - encoding: Encoding, - formats: &[FileEntryFormat], -) -> Result<FileEntry<R>> { - let mut path_name = None; - let mut directory_index = 0; - let mut timestamp = 0; - let mut size = 0; - let mut md5 = [0; 16]; - - for format in formats { - let value = parse_attribute(input, encoding, format.form)?; - match format.content_type { - constants::DW_LNCT_path => path_name = Some(value), - constants::DW_LNCT_directory_index => { - if let Some(value) = value.udata_value() { - directory_index = value; - } - } - constants::DW_LNCT_timestamp => { - if let Some(value) = value.udata_value() { - timestamp = value; - } - } - constants::DW_LNCT_size => { - if let Some(value) = value.udata_value() { - size = value; - } - } - constants::DW_LNCT_MD5 => { - if let AttributeValue::Block(mut value) = value { - if value.len().into_u64() == 16 { - md5 = value.read_u8_array()?; - } - } - } - // Ignore unknown content types. - _ => {} - } - } - - Ok(FileEntry { - path_name: path_name.unwrap(), - directory_index, - timestamp, - size, - md5, - }) -} - -// TODO: this should be shared with unit::parse_attribute(), but that is hard to do. -fn parse_attribute<R: Reader>( - input: &mut R, - encoding: Encoding, - form: constants::DwForm, -) -> Result<AttributeValue<R>> { - Ok(match form { - constants::DW_FORM_block1 => { - let len = input.read_u8().map(R::Offset::from_u8)?; - let block = input.split(len)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block2 => { - let len = input.read_u16().map(R::Offset::from_u16)?; - let block = input.split(len)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block4 => { - let len = input.read_u32().map(R::Offset::from_u32)?; - let block = input.split(len)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block => { - let len = input.read_uleb128().and_then(R::Offset::from_u64)?; - let block = input.split(len)?; - AttributeValue::Block(block) - } - constants::DW_FORM_data1 => { - let data = input.read_u8()?; - AttributeValue::Data1(data) - } - constants::DW_FORM_data2 => { - let data = input.read_u16()?; - AttributeValue::Data2(data) - } - constants::DW_FORM_data4 => { - let data = input.read_u32()?; - AttributeValue::Data4(data) - } - constants::DW_FORM_data8 => { - let data = input.read_u64()?; - AttributeValue::Data8(data) - } - constants::DW_FORM_data16 => { - let block = input.split(R::Offset::from_u8(16))?; - AttributeValue::Block(block) - } - constants::DW_FORM_udata => { - let data = input.read_uleb128()?; - AttributeValue::Udata(data) - } - constants::DW_FORM_sdata => { - let data = input.read_sleb128()?; - AttributeValue::Sdata(data) - } - constants::DW_FORM_flag => { - let present = input.read_u8()?; - AttributeValue::Flag(present != 0) - } - constants::DW_FORM_sec_offset => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::SecOffset(offset) - } - constants::DW_FORM_string => { - let string = input.read_null_terminated_slice()?; - AttributeValue::String(string) - } - constants::DW_FORM_strp => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugStrRef(DebugStrOffset(offset)) - } - constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugStrRefSup(DebugStrOffset(offset)) - } - constants::DW_FORM_line_strp => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset)) - } - constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx1 => { - let index = input.read_u8().map(R::Offset::from_u8)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx2 => { - let index = input.read_u16().map(R::Offset::from_u16)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx3 => { - let index = input.read_uint(3).and_then(R::Offset::from_u64)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx4 => { - let index = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - _ => { - return Err(Error::UnknownForm); - } - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::constants; - use crate::endianity::LittleEndian; - use crate::read::{EndianSlice, Error}; - use crate::test_util::GimliSectionMethods; - use core::u64; - use core::u8; - use test_assembler::{Endian, Label, LabelMaker, Section}; - - #[test] - fn test_parse_debug_line_32_ok() { - #[rustfmt::skip] - let buf = [ - // 32-bit length = 62. - 0x3e, 0x00, 0x00, 0x00, - // Version. - 0x04, 0x00, - // Header length = 40. - 0x28, 0x00, 0x00, 0x00, - // Minimum instruction length. - 0x01, - // Maximum operations per byte. - 0x01, - // Default is_stmt. - 0x01, - // Line base. - 0x00, - // Line range. - 0x01, - // Opcode base. - 0x03, - // Standard opcode lengths for opcodes 1 .. opcode base - 1. - 0x01, 0x02, - // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' - 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, - // File names - // foo.rs - 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, - 0x00, - 0x00, - 0x00, - // bar.h - 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, - 0x01, - 0x00, - 0x00, - // End file names. - 0x00, - - // Dummy line program data. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy next line program. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ]; - - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let comp_dir = EndianSlice::new(b"/comp_dir", LittleEndian); - let comp_name = EndianSlice::new(b"/comp_name", LittleEndian); - - let header = - LineProgramHeader::parse(rest, DebugLineOffset(0), 4, Some(comp_dir), Some(comp_name)) - .expect("should parse header ok"); - - assert_eq!( - *rest, - EndianSlice::new(&buf[buf.len() - 16..], LittleEndian) - ); - - assert_eq!(header.offset, DebugLineOffset(0)); - assert_eq!(header.version(), 4); - assert_eq!(header.minimum_instruction_length(), 1); - assert_eq!(header.maximum_operations_per_instruction(), 1); - assert_eq!(header.default_is_stmt(), true); - assert_eq!(header.line_base(), 0); - assert_eq!(header.line_range(), 1); - assert_eq!(header.opcode_base(), 3); - assert_eq!(header.directory(0), Some(AttributeValue::String(comp_dir))); - assert_eq!( - header.file(0).unwrap().path_name, - AttributeValue::String(comp_name) - ); - - let expected_lengths = [1, 2]; - assert_eq!(header.standard_opcode_lengths().slice(), &expected_lengths); - - let expected_include_directories = [ - AttributeValue::String(EndianSlice::new(b"/inc", LittleEndian)), - AttributeValue::String(EndianSlice::new(b"/inc2", LittleEndian)), - ]; - assert_eq!(header.include_directories(), &expected_include_directories); - - let expected_file_names = [ - FileEntry { - path_name: AttributeValue::String(EndianSlice::new(b"foo.rs", LittleEndian)), - directory_index: 0, - timestamp: 0, - size: 0, - md5: [0; 16], - }, - FileEntry { - path_name: AttributeValue::String(EndianSlice::new(b"bar.h", LittleEndian)), - directory_index: 1, - timestamp: 0, - size: 0, - md5: [0; 16], - }, - ]; - assert_eq!(&*header.file_names(), &expected_file_names); - } - - #[test] - fn test_parse_debug_line_header_length_too_short() { - #[rustfmt::skip] - let buf = [ - // 32-bit length = 62. - 0x3e, 0x00, 0x00, 0x00, - // Version. - 0x04, 0x00, - // Header length = 20. TOO SHORT!!! - 0x15, 0x00, 0x00, 0x00, - // Minimum instruction length. - 0x01, - // Maximum operations per byte. - 0x01, - // Default is_stmt. - 0x01, - // Line base. - 0x00, - // Line range. - 0x01, - // Opcode base. - 0x03, - // Standard opcode lengths for opcodes 1 .. opcode base - 1. - 0x01, 0x02, - // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' - 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, - // File names - // foo.rs - 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, - 0x00, - 0x00, - 0x00, - // bar.h - 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, - 0x01, - 0x00, - 0x00, - // End file names. - 0x00, - - // Dummy line program data. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy next line program. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ]; - - let input = &mut EndianSlice::new(&buf, LittleEndian); - - match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) { - Err(Error::UnexpectedEof(_)) => return, - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - fn test_parse_debug_line_unit_length_too_short() { - #[rustfmt::skip] - let buf = [ - // 32-bit length = 40. TOO SHORT!!! - 0x28, 0x00, 0x00, 0x00, - // Version. - 0x04, 0x00, - // Header length = 40. - 0x28, 0x00, 0x00, 0x00, - // Minimum instruction length. - 0x01, - // Maximum operations per byte. - 0x01, - // Default is_stmt. - 0x01, - // Line base. - 0x00, - // Line range. - 0x01, - // Opcode base. - 0x03, - // Standard opcode lengths for opcodes 1 .. opcode base - 1. - 0x01, 0x02, - // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' - 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, - // File names - // foo.rs - 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, - 0x00, - 0x00, - 0x00, - // bar.h - 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, - 0x01, - 0x00, - 0x00, - // End file names. - 0x00, - - // Dummy line program data. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // Dummy next line program. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ]; - - let input = &mut EndianSlice::new(&buf, LittleEndian); - - match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) { - Err(Error::UnexpectedEof(_)) => return, - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - const OPCODE_BASE: u8 = 13; - const STANDARD_OPCODE_LENGTHS: &[u8] = &[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1]; - - fn make_test_header( - buf: EndianSlice<LittleEndian>, - ) -> LineProgramHeader<EndianSlice<LittleEndian>> { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - let line_encoding = LineEncoding { - line_base: -3, - line_range: 12, - ..Default::default() - }; - LineProgramHeader { - encoding, - offset: DebugLineOffset(0), - unit_length: 1, - header_length: 1, - line_encoding, - opcode_base: OPCODE_BASE, - standard_opcode_lengths: EndianSlice::new(STANDARD_OPCODE_LENGTHS, LittleEndian), - file_names: vec![ - FileEntry { - path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)), - directory_index: 0, - timestamp: 0, - size: 0, - md5: [0; 16], - }, - FileEntry { - path_name: AttributeValue::String(EndianSlice::new(b"bar.rs", LittleEndian)), - directory_index: 0, - timestamp: 0, - size: 0, - md5: [0; 16], - }, - ], - include_directories: vec![], - directory_entry_format: vec![], - file_name_entry_format: vec![], - program_buf: buf, - comp_dir: None, - comp_file: None, - } - } - - fn make_test_program( - buf: EndianSlice<LittleEndian>, - ) -> IncompleteLineProgram<EndianSlice<LittleEndian>> { - IncompleteLineProgram { - header: make_test_header(buf), - } - } - - #[test] - fn test_parse_special_opcodes() { - for i in OPCODE_BASE..u8::MAX { - let input = [i, 0, 0, 0]; - let input = EndianSlice::new(&input, LittleEndian); - let header = make_test_header(input); - - let mut rest = input; - let opcode = - LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); - - assert_eq!(*rest, *input.range_from(1..)); - assert_eq!(opcode, LineInstruction::Special(i)); - } - } - - #[test] - fn test_parse_standard_opcodes() { - fn test<Operands>( - raw: constants::DwLns, - operands: Operands, - expected: LineInstruction<EndianSlice<LittleEndian>>, - ) where - Operands: AsRef<[u8]>, - { - let mut input = Vec::new(); - input.push(raw.0); - input.extend_from_slice(operands.as_ref()); - - let expected_rest = [0, 1, 2, 3, 4]; - input.extend_from_slice(&expected_rest); - - let input = EndianSlice::new(&*input, LittleEndian); - let header = make_test_header(input); - - let mut rest = input; - let opcode = - LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); - - assert_eq!(opcode, expected); - assert_eq!(*rest, expected_rest); - } - - test(constants::DW_LNS_copy, [], LineInstruction::Copy); - test( - constants::DW_LNS_advance_pc, - [42], - LineInstruction::AdvancePc(42), - ); - test( - constants::DW_LNS_advance_line, - [9], - LineInstruction::AdvanceLine(9), - ); - test(constants::DW_LNS_set_file, [7], LineInstruction::SetFile(7)); - test( - constants::DW_LNS_set_column, - [1], - LineInstruction::SetColumn(1), - ); - test( - constants::DW_LNS_negate_stmt, - [], - LineInstruction::NegateStatement, - ); - test( - constants::DW_LNS_set_basic_block, - [], - LineInstruction::SetBasicBlock, - ); - test( - constants::DW_LNS_const_add_pc, - [], - LineInstruction::ConstAddPc, - ); - test( - constants::DW_LNS_fixed_advance_pc, - [42, 0], - LineInstruction::FixedAddPc(42), - ); - test( - constants::DW_LNS_set_prologue_end, - [], - LineInstruction::SetPrologueEnd, - ); - test( - constants::DW_LNS_set_isa, - [57 + 0x80, 100], - LineInstruction::SetIsa(12857), - ); - } - - #[test] - fn test_parse_unknown_standard_opcode_no_args() { - let input = [OPCODE_BASE, 1, 2, 3]; - let input = EndianSlice::new(&input, LittleEndian); - let mut standard_opcode_lengths = Vec::new(); - let mut header = make_test_header(input); - standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); - standard_opcode_lengths.push(0); - header.opcode_base += 1; - header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); - - let mut rest = input; - let opcode = - LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); - - assert_eq!( - opcode, - LineInstruction::UnknownStandard0(constants::DwLns(OPCODE_BASE)) - ); - assert_eq!(*rest, *input.range_from(1..)); - } - - #[test] - fn test_parse_unknown_standard_opcode_one_arg() { - let input = [OPCODE_BASE, 1, 2, 3]; - let input = EndianSlice::new(&input, LittleEndian); - let mut standard_opcode_lengths = Vec::new(); - let mut header = make_test_header(input); - standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); - standard_opcode_lengths.push(1); - header.opcode_base += 1; - header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); - - let mut rest = input; - let opcode = - LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); - - assert_eq!( - opcode, - LineInstruction::UnknownStandard1(constants::DwLns(OPCODE_BASE), 1) - ); - assert_eq!(*rest, *input.range_from(2..)); - } - - #[test] - fn test_parse_unknown_standard_opcode_many_args() { - let input = [OPCODE_BASE, 1, 2, 3]; - let input = EndianSlice::new(&input, LittleEndian); - let args = input.range_from(1..); - let mut standard_opcode_lengths = Vec::new(); - let mut header = make_test_header(input); - standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); - standard_opcode_lengths.push(3); - header.opcode_base += 1; - header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); - - let mut rest = input; - let opcode = - LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); - - assert_eq!( - opcode, - LineInstruction::UnknownStandardN(constants::DwLns(OPCODE_BASE), args) - ); - assert_eq!(*rest, []); - } - - #[test] - fn test_parse_extended_opcodes() { - fn test<Operands>( - raw: constants::DwLne, - operands: Operands, - expected: LineInstruction<EndianSlice<LittleEndian>>, - ) where - Operands: AsRef<[u8]>, - { - let mut input = Vec::new(); - input.push(0); - - let operands = operands.as_ref(); - input.push(1 + operands.len() as u8); - - input.push(raw.0); - input.extend_from_slice(operands); - - let expected_rest = [0, 1, 2, 3, 4]; - input.extend_from_slice(&expected_rest); - - let input = EndianSlice::new(&input, LittleEndian); - let header = make_test_header(input); - - let mut rest = input; - let opcode = - LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); - - assert_eq!(opcode, expected); - assert_eq!(*rest, expected_rest); - } - - test( - constants::DW_LNE_end_sequence, - [], - LineInstruction::EndSequence, - ); - test( - constants::DW_LNE_set_address, - [1, 2, 3, 4, 5, 6, 7, 8], - LineInstruction::SetAddress(578_437_695_752_307_201), - ); - test( - constants::DW_LNE_set_discriminator, - [42], - LineInstruction::SetDiscriminator(42), - ); - - let mut file = Vec::new(); - // "foo.c" - let path_name = [b'f', b'o', b'o', b'.', b'c', 0]; - file.extend_from_slice(&path_name); - // Directory index. - file.push(0); - // Last modification of file. - file.push(1); - // Size of file. - file.push(2); - - test( - constants::DW_LNE_define_file, - file, - LineInstruction::DefineFile(FileEntry { - path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)), - directory_index: 0, - timestamp: 1, - size: 2, - md5: [0; 16], - }), - ); - - // Unknown extended opcode. - let operands = [1, 2, 3, 4, 5, 6]; - let opcode = constants::DwLne(99); - test( - opcode, - operands, - LineInstruction::UnknownExtended(opcode, EndianSlice::new(&operands, LittleEndian)), - ); - } - - #[test] - fn test_file_entry_directory() { - let path_name = [b'f', b'o', b'o', b'.', b'r', b's', 0]; - - let mut file = FileEntry { - path_name: AttributeValue::String(EndianSlice::new(&path_name, LittleEndian)), - directory_index: 1, - timestamp: 0, - size: 0, - md5: [0; 16], - }; - - let mut header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let dir = AttributeValue::String(EndianSlice::new(b"dir", LittleEndian)); - header.include_directories.push(dir); - - assert_eq!(file.directory(&header), Some(dir)); - - // Now test the compilation's current directory. - file.directory_index = 0; - assert_eq!(file.directory(&header), None); - } - - fn assert_exec_opcode<'input>( - header: LineProgramHeader<EndianSlice<'input, LittleEndian>>, - mut registers: LineRow, - opcode: LineInstruction<EndianSlice<'input, LittleEndian>>, - expected_registers: LineRow, - expect_new_row: bool, - ) { - let mut program = IncompleteLineProgram { header }; - let is_new_row = registers.execute(opcode, &mut program); - - assert_eq!(is_new_row, expect_new_row); - assert_eq!(registers, expected_registers); - } - - #[test] - fn test_exec_special_noop() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::Special(16); - let expected_registers = initial_registers; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_special_negative_line_advance() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let mut initial_registers = LineRow::new(&header); - initial_registers.line.0 = 10; - - let opcode = LineInstruction::Special(13); - - let mut expected_registers = initial_registers; - expected_registers.line.0 -= 3; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_special_positive_line_advance() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let initial_registers = LineRow::new(&header); - - let opcode = LineInstruction::Special(19); - - let mut expected_registers = initial_registers; - expected_registers.line.0 += 3; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_special_positive_address_advance() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let initial_registers = LineRow::new(&header); - - let opcode = LineInstruction::Special(52); - - let mut expected_registers = initial_registers; - expected_registers.address.0 += 3; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_special_positive_address_and_line_advance() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let initial_registers = LineRow::new(&header); - - let opcode = LineInstruction::Special(55); - - let mut expected_registers = initial_registers; - expected_registers.address.0 += 3; - expected_registers.line.0 += 3; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_special_positive_address_and_negative_line_advance() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let mut initial_registers = LineRow::new(&header); - initial_registers.line.0 = 10; - - let opcode = LineInstruction::Special(49); - - let mut expected_registers = initial_registers; - expected_registers.address.0 += 3; - expected_registers.line.0 -= 3; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_special_line_underflow() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let mut initial_registers = LineRow::new(&header); - initial_registers.line.0 = 2; - - // -3 line advance. - let opcode = LineInstruction::Special(13); - - let mut expected_registers = initial_registers; - // Clamp at 0. No idea if this is the best way to handle this situation - // or not... - expected_registers.line.0 = 0; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_copy() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let mut initial_registers = LineRow::new(&header); - initial_registers.address.0 = 1337; - initial_registers.line.0 = 42; - - let opcode = LineInstruction::Copy; - - let expected_registers = initial_registers; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_advance_pc() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::AdvancePc(42); - - let mut expected_registers = initial_registers; - expected_registers.address.0 += 42; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_advance_pc_overflow() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let opcode = LineInstruction::AdvancePc(42); - - let mut initial_registers = LineRow::new(&header); - initial_registers.address.0 = u64::MAX; - - let mut expected_registers = initial_registers; - expected_registers.address.0 = 41; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_advance_line() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::AdvanceLine(42); - - let mut expected_registers = initial_registers; - expected_registers.line.0 += 42; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_advance_line_overflow() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let opcode = LineInstruction::AdvanceLine(42); - - let mut initial_registers = LineRow::new(&header); - initial_registers.line.0 = u64::MAX; - - let mut expected_registers = initial_registers; - expected_registers.line.0 = 41; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_set_file_in_bounds() { - for file_idx in 1..3 { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::SetFile(file_idx); - - let mut expected_registers = initial_registers; - expected_registers.file = file_idx; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - } - - #[test] - fn test_exec_set_file_out_of_bounds() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::SetFile(100); - - // The spec doesn't say anything about rejecting input programs - // that set the file register out of bounds of the actual number - // of files that have been defined. Instead, we cross our - // fingers and hope that one gets defined before - // `LineRow::file` gets called and handle the error at - // that time if need be. - let mut expected_registers = initial_registers; - expected_registers.file = 100; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_file_entry_file_index_out_of_bounds() { - // These indices are 1-based, so 0 is invalid. 100 is way more than the - // number of files defined in the header. - let out_of_bounds_indices = [0, 100]; - - for file_idx in &out_of_bounds_indices[..] { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let mut row = LineRow::new(&header); - - row.file = *file_idx; - - assert_eq!(row.file(&header), None); - } - } - - #[test] - fn test_file_entry_file_index_in_bounds() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let mut row = LineRow::new(&header); - - row.file = 2; - - assert_eq!(row.file(&header), Some(&header.file_names()[1])); - } - - #[test] - fn test_exec_set_column() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::SetColumn(42); - - let mut expected_registers = initial_registers; - expected_registers.column = 42; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_negate_statement() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::NegateStatement; - - let mut expected_registers = initial_registers; - expected_registers.is_stmt = !initial_registers.is_stmt; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_set_basic_block() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let mut initial_registers = LineRow::new(&header); - initial_registers.basic_block = false; - - let opcode = LineInstruction::SetBasicBlock; - - let mut expected_registers = initial_registers; - expected_registers.basic_block = true; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_const_add_pc() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::ConstAddPc; - - let mut expected_registers = initial_registers; - expected_registers.address.0 += 20; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_fixed_add_pc() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let mut initial_registers = LineRow::new(&header); - initial_registers.op_index.0 = 1; - - let opcode = LineInstruction::FixedAddPc(10); - - let mut expected_registers = initial_registers; - expected_registers.address.0 += 10; - expected_registers.op_index.0 = 0; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_set_prologue_end() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - - let mut initial_registers = LineRow::new(&header); - initial_registers.prologue_end = false; - - let opcode = LineInstruction::SetPrologueEnd; - - let mut expected_registers = initial_registers; - expected_registers.prologue_end = true; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_set_isa() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::SetIsa(1993); - - let mut expected_registers = initial_registers; - expected_registers.isa = 1993; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_unknown_standard_0() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::UnknownStandard0(constants::DwLns(111)); - let expected_registers = initial_registers; - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_unknown_standard_1() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::UnknownStandard1(constants::DwLns(111), 2); - let expected_registers = initial_registers; - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_unknown_standard_n() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::UnknownStandardN( - constants::DwLns(111), - EndianSlice::new(&[2, 2, 2], LittleEndian), - ); - let expected_registers = initial_registers; - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_end_sequence() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::EndSequence; - - let mut expected_registers = initial_registers; - expected_registers.end_sequence = true; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); - } - - #[test] - fn test_exec_set_address() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::SetAddress(3030); - - let mut expected_registers = initial_registers; - expected_registers.address.0 = 3030; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_set_address_tombstone() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::SetAddress(!0); - - let mut expected_registers = initial_registers; - expected_registers.tombstone = true; - expected_registers.address.0 = !0; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_define_file() { - let mut program = make_test_program(EndianSlice::new(&[], LittleEndian)); - let mut row = LineRow::new(program.header()); - - let file = FileEntry { - path_name: AttributeValue::String(EndianSlice::new(b"test.cpp", LittleEndian)), - directory_index: 0, - timestamp: 0, - size: 0, - md5: [0; 16], - }; - - let opcode = LineInstruction::DefineFile(file); - let is_new_row = row.execute(opcode, &mut program); - - assert_eq!(is_new_row, false); - assert_eq!(Some(&file), program.header().file_names.last()); - } - - #[test] - fn test_exec_set_discriminator() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::SetDiscriminator(9); - - let mut expected_registers = initial_registers; - expected_registers.discriminator = 9; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - #[test] - fn test_exec_unknown_extended() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); - let initial_registers = LineRow::new(&header); - let opcode = LineInstruction::UnknownExtended( - constants::DwLne(74), - EndianSlice::new(&[], LittleEndian), - ); - let expected_registers = initial_registers; - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); - } - - /// Ensure that `LineRows<R,P>` is covariant wrt R. - /// This only needs to compile. - #[allow(dead_code, unreachable_code, unused_variables)] - fn test_line_rows_variance<'a, 'b>(_: &'a [u8], _: &'b [u8]) - where - 'a: 'b, - { - let a: &OneShotLineRows<EndianSlice<'a, LittleEndian>> = unimplemented!(); - let _: &OneShotLineRows<EndianSlice<'b, LittleEndian>> = a; - } - - #[test] - fn test_parse_debug_line_v5_ok() { - let expected_lengths = &[1, 2]; - let expected_program = &[0, 1, 2, 3, 4]; - let expected_rest = &[5, 6, 7, 8, 9]; - let expected_include_directories = [ - AttributeValue::String(EndianSlice::new(b"dir1", LittleEndian)), - AttributeValue::String(EndianSlice::new(b"dir2", LittleEndian)), - ]; - let expected_file_names = [ - FileEntry { - path_name: AttributeValue::String(EndianSlice::new(b"file1", LittleEndian)), - directory_index: 0, - timestamp: 0, - size: 0, - md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - }, - FileEntry { - path_name: AttributeValue::String(EndianSlice::new(b"file2", LittleEndian)), - directory_index: 1, - timestamp: 0, - size: 0, - md5: [ - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - ], - }, - ]; - - for format in vec![Format::Dwarf32, Format::Dwarf64] { - let length = Label::new(); - let header_length = Label::new(); - let start = Label::new(); - let header_start = Label::new(); - let end = Label::new(); - let header_end = Label::new(); - let section = Section::with_endian(Endian::Little) - .initial_length(format, &length, &start) - .D16(5) - // Address size. - .D8(4) - // Segment selector size. - .D8(0) - .word_label(format.word_size(), &header_length) - .mark(&header_start) - // Minimum instruction length. - .D8(1) - // Maximum operations per byte. - .D8(1) - // Default is_stmt. - .D8(1) - // Line base. - .D8(0) - // Line range. - .D8(1) - // Opcode base. - .D8(expected_lengths.len() as u8 + 1) - // Standard opcode lengths for opcodes 1 .. opcode base - 1. - .append_bytes(expected_lengths) - // Directory entry format count. - .D8(1) - .uleb(constants::DW_LNCT_path.0 as u64) - .uleb(constants::DW_FORM_string.0 as u64) - // Directory count. - .D8(2) - .append_bytes(b"dir1\0") - .append_bytes(b"dir2\0") - // File entry format count. - .D8(3) - .uleb(constants::DW_LNCT_path.0 as u64) - .uleb(constants::DW_FORM_string.0 as u64) - .uleb(constants::DW_LNCT_directory_index.0 as u64) - .uleb(constants::DW_FORM_data1.0 as u64) - .uleb(constants::DW_LNCT_MD5.0 as u64) - .uleb(constants::DW_FORM_data16.0 as u64) - // File count. - .D8(2) - .append_bytes(b"file1\0") - .D8(0) - .append_bytes(&expected_file_names[0].md5) - .append_bytes(b"file2\0") - .D8(1) - .append_bytes(&expected_file_names[1].md5) - .mark(&header_end) - // Dummy line program data. - .append_bytes(expected_program) - .mark(&end) - // Dummy trailing data. - .append_bytes(expected_rest); - length.set_const((&end - &start) as u64); - header_length.set_const((&header_end - &header_start) as u64); - let section = section.get_contents().unwrap(); - - let input = &mut EndianSlice::new(§ion, LittleEndian); - - let header = LineProgramHeader::parse(input, DebugLineOffset(0), 0, None, None) - .expect("should parse header ok"); - - assert_eq!(header.raw_program_buf().slice(), expected_program); - assert_eq!(input.slice(), expected_rest); - - assert_eq!(header.offset, DebugLineOffset(0)); - assert_eq!(header.version(), 5); - assert_eq!(header.address_size(), 4); - assert_eq!(header.minimum_instruction_length(), 1); - assert_eq!(header.maximum_operations_per_instruction(), 1); - assert_eq!(header.default_is_stmt(), true); - assert_eq!(header.line_base(), 0); - assert_eq!(header.line_range(), 1); - assert_eq!(header.opcode_base(), expected_lengths.len() as u8 + 1); - assert_eq!(header.standard_opcode_lengths().slice(), expected_lengths); - assert_eq!( - header.directory_entry_format(), - &[FileEntryFormat { - content_type: constants::DW_LNCT_path, - form: constants::DW_FORM_string, - }] - ); - assert_eq!(header.include_directories(), expected_include_directories); - assert_eq!(header.directory(0), Some(expected_include_directories[0])); - assert_eq!( - header.file_name_entry_format(), - &[ - FileEntryFormat { - content_type: constants::DW_LNCT_path, - form: constants::DW_FORM_string, - }, - FileEntryFormat { - content_type: constants::DW_LNCT_directory_index, - form: constants::DW_FORM_data1, - }, - FileEntryFormat { - content_type: constants::DW_LNCT_MD5, - form: constants::DW_FORM_data16, - } - ] - ); - assert_eq!(header.file_names(), expected_file_names); - assert_eq!(header.file(0), Some(&expected_file_names[0])); - } - } - - #[test] - fn test_sequences() { - #[rustfmt::skip] - let buf = [ - // 32-bit length - 94, 0x00, 0x00, 0x00, - // Version. - 0x04, 0x00, - // Header length = 40. - 0x28, 0x00, 0x00, 0x00, - // Minimum instruction length. - 0x01, - // Maximum operations per byte. - 0x01, - // Default is_stmt. - 0x01, - // Line base. - 0x00, - // Line range. - 0x01, - // Opcode base. - 0x03, - // Standard opcode lengths for opcodes 1 .. opcode base - 1. - 0x01, 0x02, - // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' - 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, - // File names - // foo.rs - 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, - 0x00, - 0x00, - 0x00, - // bar.h - 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, - 0x01, - 0x00, - 0x00, - // End file names. - 0x00, - - 0, 5, constants::DW_LNE_set_address.0, 1, 0, 0, 0, - constants::DW_LNS_copy.0, - constants::DW_LNS_advance_pc.0, 1, - constants::DW_LNS_copy.0, - constants::DW_LNS_advance_pc.0, 2, - 0, 1, constants::DW_LNE_end_sequence.0, - - // Tombstone - 0, 5, constants::DW_LNE_set_address.0, 0xff, 0xff, 0xff, 0xff, - constants::DW_LNS_copy.0, - constants::DW_LNS_advance_pc.0, 1, - constants::DW_LNS_copy.0, - constants::DW_LNS_advance_pc.0, 2, - 0, 1, constants::DW_LNE_end_sequence.0, - - 0, 5, constants::DW_LNE_set_address.0, 11, 0, 0, 0, - constants::DW_LNS_copy.0, - constants::DW_LNS_advance_pc.0, 1, - constants::DW_LNS_copy.0, - constants::DW_LNS_advance_pc.0, 2, - 0, 1, constants::DW_LNE_end_sequence.0, - ]; - assert_eq!(buf[0] as usize, buf.len() - 4); - - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - let header = LineProgramHeader::parse(rest, DebugLineOffset(0), 4, None, None) - .expect("should parse header ok"); - let program = IncompleteLineProgram { header }; - - let sequences = program.sequences().unwrap().1; - assert_eq!(sequences.len(), 2); - assert_eq!(sequences[0].start, 1); - assert_eq!(sequences[0].end, 4); - assert_eq!(sequences[1].start, 11); - assert_eq!(sequences[1].end, 14); - } -} diff --git a/vendor/gimli/src/read/lists.rs b/vendor/gimli/src/read/lists.rs deleted file mode 100644 index 898a757..0000000 --- a/vendor/gimli/src/read/lists.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::common::{Encoding, Format}; -use crate::read::{Error, Reader, Result}; - -#[derive(Debug, Clone, Copy)] -pub(crate) struct ListsHeader { - encoding: Encoding, - #[allow(dead_code)] - offset_entry_count: u32, -} - -impl Default for ListsHeader { - fn default() -> Self { - ListsHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 0, - }, - offset_entry_count: 0, - } - } -} - -impl ListsHeader { - /// Return the serialized size of the table header. - #[allow(dead_code)] - #[inline] - fn size(self) -> u8 { - // initial_length + version + address_size + segment_selector_size + offset_entry_count - ListsHeader::size_for_encoding(self.encoding) - } - - /// Return the serialized size of the table header. - #[inline] - pub(crate) fn size_for_encoding(encoding: Encoding) -> u8 { - // initial_length + version + address_size + segment_selector_size + offset_entry_count - encoding.format.initial_length_size() + 2 + 1 + 1 + 4 - } -} - -// TODO: add an iterator over headers in the appropriate sections section -#[allow(dead_code)] -fn parse_header<R: Reader>(input: &mut R) -> Result<ListsHeader> { - let (length, format) = input.read_initial_length()?; - input.truncate(length)?; - - let version = input.read_u16()?; - if version != 5 { - return Err(Error::UnknownVersion(u64::from(version))); - } - - let address_size = input.read_u8()?; - let segment_selector_size = input.read_u8()?; - if segment_selector_size != 0 { - return Err(Error::UnsupportedSegmentSize); - } - let offset_entry_count = input.read_u32()?; - - let encoding = Encoding { - format, - version, - address_size, - }; - Ok(ListsHeader { - encoding, - offset_entry_count, - }) -} diff --git a/vendor/gimli/src/read/loclists.rs b/vendor/gimli/src/read/loclists.rs deleted file mode 100644 index 5cba675..0000000 --- a/vendor/gimli/src/read/loclists.rs +++ /dev/null @@ -1,1627 +0,0 @@ -use crate::common::{ - DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, DwarfFileType, Encoding, - LocationListsOffset, SectionId, -}; -use crate::constants; -use crate::endianity::Endianity; -use crate::read::{ - lists::ListsHeader, DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader, - ReaderOffset, ReaderOffsetId, Result, Section, -}; - -/// The raw contents of the `.debug_loc` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugLoc<R> { - pub(crate) section: R, -} - -impl<'input, Endian> DebugLoc<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugLoc` instance from the data in the `.debug_loc` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_loc` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugLoc, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_loc_section_somehow = || &buf; - /// let debug_loc = DebugLoc::new(read_debug_loc_section_somehow(), LittleEndian); - /// ``` - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R> Section<R> for DebugLoc<R> { - fn id() -> SectionId { - SectionId::DebugLoc - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugLoc<R> { - fn from(section: R) -> Self { - DebugLoc { section } - } -} - -/// The `DebugLocLists` struct represents the DWARF data -/// found in the `.debug_loclists` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugLocLists<R> { - section: R, -} - -impl<'input, Endian> DebugLocLists<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugLocLists` instance from the data in the `.debug_loclists` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_loclists` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugLocLists, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_loclists_section_somehow = || &buf; - /// let debug_loclists = DebugLocLists::new(read_debug_loclists_section_somehow(), LittleEndian); - /// ``` - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R> Section<R> for DebugLocLists<R> { - fn id() -> SectionId { - SectionId::DebugLocLists - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugLocLists<R> { - fn from(section: R) -> Self { - DebugLocLists { section } - } -} - -pub(crate) type LocListsHeader = ListsHeader; - -impl<Offset> DebugLocListsBase<Offset> -where - Offset: ReaderOffset, -{ - /// Returns a `DebugLocListsBase` with the default value of DW_AT_loclists_base - /// for the given `Encoding` and `DwarfFileType`. - pub fn default_for_encoding_and_file( - encoding: Encoding, - file_type: DwarfFileType, - ) -> DebugLocListsBase<Offset> { - if encoding.version >= 5 && file_type == DwarfFileType::Dwo { - // In .dwo files, the compiler omits the DW_AT_loclists_base attribute (because there is - // only a single unit in the file) but we must skip past the header, which the attribute - // would normally do for us. - DebugLocListsBase(Offset::from_u8(LocListsHeader::size_for_encoding(encoding))) - } else { - DebugLocListsBase(Offset::from_u8(0)) - } - } -} - -/// The DWARF data found in `.debug_loc` and `.debug_loclists` sections. -#[derive(Debug, Default, Clone, Copy)] -pub struct LocationLists<R> { - debug_loc: DebugLoc<R>, - debug_loclists: DebugLocLists<R>, -} - -impl<R> LocationLists<R> { - /// Construct a new `LocationLists` instance from the data in the `.debug_loc` and - /// `.debug_loclists` sections. - pub fn new(debug_loc: DebugLoc<R>, debug_loclists: DebugLocLists<R>) -> LocationLists<R> { - LocationLists { - debug_loc, - debug_loclists, - } - } -} - -impl<T> LocationLists<T> { - /// Create a `LocationLists` that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::LocationLists<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> LocationLists<R> - where - F: FnMut(&'a T) -> R, - { - LocationLists { - debug_loc: borrow(&self.debug_loc.section).into(), - debug_loclists: borrow(&self.debug_loclists.section).into(), - } - } -} - -impl<R: Reader> LocationLists<R> { - /// Iterate over the `LocationListEntry`s starting at the given offset. - /// - /// The `unit_encoding` must match the compilation unit that the - /// offset was contained in. - /// - /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the - /// `DW_TAG_compile_unit` entry for the compilation unit that contains this location - /// list. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn locations( - &self, - offset: LocationListsOffset<R::Offset>, - unit_encoding: Encoding, - base_address: u64, - debug_addr: &DebugAddr<R>, - debug_addr_base: DebugAddrBase<R::Offset>, - ) -> Result<LocListIter<R>> { - Ok(LocListIter::new( - self.raw_locations(offset, unit_encoding)?, - base_address, - debug_addr.clone(), - debug_addr_base, - )) - } - - /// Similar to `locations`, but with special handling for .dwo files. - /// This should only been used when this `LocationLists` was loaded from a - /// .dwo file. - pub fn locations_dwo( - &self, - offset: LocationListsOffset<R::Offset>, - unit_encoding: Encoding, - base_address: u64, - debug_addr: &DebugAddr<R>, - debug_addr_base: DebugAddrBase<R::Offset>, - ) -> Result<LocListIter<R>> { - Ok(LocListIter::new( - self.raw_locations_dwo(offset, unit_encoding)?, - base_address, - debug_addr.clone(), - debug_addr_base, - )) - } - - /// Iterate over the raw `LocationListEntry`s starting at the given offset. - /// - /// The `unit_encoding` must match the compilation unit that the - /// offset was contained in. - /// - /// This iterator does not perform any processing of the location entries, - /// such as handling base addresses. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn raw_locations( - &self, - offset: LocationListsOffset<R::Offset>, - unit_encoding: Encoding, - ) -> Result<RawLocListIter<R>> { - let (mut input, format) = if unit_encoding.version <= 4 { - (self.debug_loc.section.clone(), LocListsFormat::Bare) - } else { - (self.debug_loclists.section.clone(), LocListsFormat::Lle) - }; - input.skip(offset.0)?; - Ok(RawLocListIter::new(input, unit_encoding, format)) - } - - /// Similar to `raw_locations`, but with special handling for .dwo files. - /// This should only been used when this `LocationLists` was loaded from a - /// .dwo file. - pub fn raw_locations_dwo( - &self, - offset: LocationListsOffset<R::Offset>, - unit_encoding: Encoding, - ) -> Result<RawLocListIter<R>> { - let mut input = if unit_encoding.version <= 4 { - // In the GNU split dwarf extension the locations are present in the - // .debug_loc section but are encoded with the DW_LLE values used - // for the DWARF 5 .debug_loclists section. - self.debug_loc.section.clone() - } else { - self.debug_loclists.section.clone() - }; - input.skip(offset.0)?; - Ok(RawLocListIter::new( - input, - unit_encoding, - LocListsFormat::Lle, - )) - } - - /// Returns the `.debug_loclists` offset at the given `base` and `index`. - /// - /// The `base` must be the `DW_AT_loclists_base` value from the compilation unit DIE. - /// This is an offset that points to the first entry following the header. - /// - /// The `index` is the value of a `DW_FORM_loclistx` attribute. - pub fn get_offset( - &self, - unit_encoding: Encoding, - base: DebugLocListsBase<R::Offset>, - index: DebugLocListsIndex<R::Offset>, - ) -> Result<LocationListsOffset<R::Offset>> { - let format = unit_encoding.format; - let input = &mut self.debug_loclists.section.clone(); - input.skip(base.0)?; - input.skip(R::Offset::from_u64( - index.0.into_u64() * u64::from(format.word_size()), - )?)?; - input - .read_offset(format) - .map(|x| LocationListsOffset(base.0 + x)) - } - - /// Call `Reader::lookup_offset_id` for each section, and return the first match. - pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> { - self.debug_loc - .lookup_offset_id(id) - .or_else(|| self.debug_loclists.lookup_offset_id(id)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum LocListsFormat { - /// The bare location list format used before DWARF 5. - Bare, - /// The DW_LLE encoded range list format used in DWARF 5 and the non-standard GNU - /// split dwarf extension. - Lle, -} - -/// A raw iterator over a location list. -/// -/// This iterator does not perform any processing of the location entries, -/// such as handling base addresses. -#[derive(Debug)] -pub struct RawLocListIter<R: Reader> { - input: R, - encoding: Encoding, - format: LocListsFormat, -} - -/// A raw entry in .debug_loclists. -#[derive(Clone, Debug)] -pub enum RawLocListEntry<R: Reader> { - /// A location from DWARF version <= 4. - AddressOrOffsetPair { - /// Start of range. May be an address or an offset. - begin: u64, - /// End of range. May be an address or an offset. - end: u64, - /// expression - data: Expression<R>, - }, - /// DW_LLE_base_address - BaseAddress { - /// base address - addr: u64, - }, - /// DW_LLE_base_addressx - BaseAddressx { - /// base address - addr: DebugAddrIndex<R::Offset>, - }, - /// DW_LLE_startx_endx - StartxEndx { - /// start of range - begin: DebugAddrIndex<R::Offset>, - /// end of range - end: DebugAddrIndex<R::Offset>, - /// expression - data: Expression<R>, - }, - /// DW_LLE_startx_length - StartxLength { - /// start of range - begin: DebugAddrIndex<R::Offset>, - /// length of range - length: u64, - /// expression - data: Expression<R>, - }, - /// DW_LLE_offset_pair - OffsetPair { - /// start of range - begin: u64, - /// end of range - end: u64, - /// expression - data: Expression<R>, - }, - /// DW_LLE_default_location - DefaultLocation { - /// expression - data: Expression<R>, - }, - /// DW_LLE_start_end - StartEnd { - /// start of range - begin: u64, - /// end of range - end: u64, - /// expression - data: Expression<R>, - }, - /// DW_LLE_start_length - StartLength { - /// start of range - begin: u64, - /// length of range - length: u64, - /// expression - data: Expression<R>, - }, -} - -fn parse_data<R: Reader>(input: &mut R, encoding: Encoding) -> Result<Expression<R>> { - if encoding.version >= 5 { - let len = R::Offset::from_u64(input.read_uleb128()?)?; - Ok(Expression(input.split(len)?)) - } else { - // In the GNU split-dwarf extension this is a fixed 2 byte value. - let len = R::Offset::from_u16(input.read_u16()?); - Ok(Expression(input.split(len)?)) - } -} - -impl<R: Reader> RawLocListEntry<R> { - /// Parse a location list entry from `.debug_loclists` - fn parse(input: &mut R, encoding: Encoding, format: LocListsFormat) -> Result<Option<Self>> { - Ok(match format { - LocListsFormat::Bare => { - let range = RawRange::parse(input, encoding.address_size)?; - if range.is_end() { - None - } else if range.is_base_address(encoding.address_size) { - Some(RawLocListEntry::BaseAddress { addr: range.end }) - } else { - let len = R::Offset::from_u16(input.read_u16()?); - let data = Expression(input.split(len)?); - Some(RawLocListEntry::AddressOrOffsetPair { - begin: range.begin, - end: range.end, - data, - }) - } - } - LocListsFormat::Lle => match constants::DwLle(input.read_u8()?) { - constants::DW_LLE_end_of_list => None, - constants::DW_LLE_base_addressx => Some(RawLocListEntry::BaseAddressx { - addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - }), - constants::DW_LLE_startx_endx => Some(RawLocListEntry::StartxEndx { - begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - data: parse_data(input, encoding)?, - }), - constants::DW_LLE_startx_length => Some(RawLocListEntry::StartxLength { - begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - length: if encoding.version >= 5 { - input.read_uleb128()? - } else { - // In the GNU split-dwarf extension this is a fixed 4 byte value. - input.read_u32()? as u64 - }, - data: parse_data(input, encoding)?, - }), - constants::DW_LLE_offset_pair => Some(RawLocListEntry::OffsetPair { - begin: input.read_uleb128()?, - end: input.read_uleb128()?, - data: parse_data(input, encoding)?, - }), - constants::DW_LLE_default_location => Some(RawLocListEntry::DefaultLocation { - data: parse_data(input, encoding)?, - }), - constants::DW_LLE_base_address => Some(RawLocListEntry::BaseAddress { - addr: input.read_address(encoding.address_size)?, - }), - constants::DW_LLE_start_end => Some(RawLocListEntry::StartEnd { - begin: input.read_address(encoding.address_size)?, - end: input.read_address(encoding.address_size)?, - data: parse_data(input, encoding)?, - }), - constants::DW_LLE_start_length => Some(RawLocListEntry::StartLength { - begin: input.read_address(encoding.address_size)?, - length: input.read_uleb128()?, - data: parse_data(input, encoding)?, - }), - _ => { - return Err(Error::InvalidAddressRange); - } - }, - }) - } -} - -impl<R: Reader> RawLocListIter<R> { - /// Construct a `RawLocListIter`. - fn new(input: R, encoding: Encoding, format: LocListsFormat) -> RawLocListIter<R> { - RawLocListIter { - input, - encoding, - format, - } - } - - /// Advance the iterator to the next location. - pub fn next(&mut self) -> Result<Option<RawLocListEntry<R>>> { - if self.input.is_empty() { - return Ok(None); - } - - match RawLocListEntry::parse(&mut self.input, self.encoding, self.format) { - Ok(entry) => { - if entry.is_none() { - self.input.empty(); - } - Ok(entry) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for RawLocListIter<R> { - type Item = RawLocListEntry<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - RawLocListIter::next(self) - } -} - -/// An iterator over a location list. -/// -/// This iterator internally handles processing of base address selection entries -/// and list end entries. Thus, it only returns location entries that are valid -/// and already adjusted for the base address. -#[derive(Debug)] -pub struct LocListIter<R: Reader> { - raw: RawLocListIter<R>, - base_address: u64, - debug_addr: DebugAddr<R>, - debug_addr_base: DebugAddrBase<R::Offset>, -} - -impl<R: Reader> LocListIter<R> { - /// Construct a `LocListIter`. - fn new( - raw: RawLocListIter<R>, - base_address: u64, - debug_addr: DebugAddr<R>, - debug_addr_base: DebugAddrBase<R::Offset>, - ) -> LocListIter<R> { - LocListIter { - raw, - base_address, - debug_addr, - debug_addr_base, - } - } - - #[inline] - fn get_address(&self, index: DebugAddrIndex<R::Offset>) -> Result<u64> { - self.debug_addr - .get_address(self.raw.encoding.address_size, self.debug_addr_base, index) - } - - /// Advance the iterator to the next location. - pub fn next(&mut self) -> Result<Option<LocationListEntry<R>>> { - loop { - let raw_loc = match self.raw.next()? { - Some(loc) => loc, - None => return Ok(None), - }; - - let loc = self.convert_raw(raw_loc)?; - if loc.is_some() { - return Ok(loc); - } - } - } - - /// Return the next raw location. - /// - /// The raw location should be passed to `convert_raw`. - #[doc(hidden)] - pub fn next_raw(&mut self) -> Result<Option<RawLocListEntry<R>>> { - self.raw.next() - } - - /// Convert a raw location into a location, and update the state of the iterator. - /// - /// The raw location should have been obtained from `next_raw`. - #[doc(hidden)] - pub fn convert_raw( - &mut self, - raw_loc: RawLocListEntry<R>, - ) -> Result<Option<LocationListEntry<R>>> { - let mask = !0 >> (64 - self.raw.encoding.address_size * 8); - let tombstone = if self.raw.encoding.version <= 4 { - mask - 1 - } else { - mask - }; - - let (range, data) = match raw_loc { - RawLocListEntry::BaseAddress { addr } => { - self.base_address = addr; - return Ok(None); - } - RawLocListEntry::BaseAddressx { addr } => { - self.base_address = self.get_address(addr)?; - return Ok(None); - } - RawLocListEntry::StartxEndx { begin, end, data } => { - let begin = self.get_address(begin)?; - let end = self.get_address(end)?; - (Range { begin, end }, data) - } - RawLocListEntry::StartxLength { - begin, - length, - data, - } => { - let begin = self.get_address(begin)?; - let end = begin.wrapping_add(length) & mask; - (Range { begin, end }, data) - } - RawLocListEntry::DefaultLocation { data } => ( - Range { - begin: 0, - end: u64::max_value(), - }, - data, - ), - RawLocListEntry::AddressOrOffsetPair { begin, end, data } - | RawLocListEntry::OffsetPair { begin, end, data } => { - if self.base_address == tombstone { - return Ok(None); - } - let mut range = Range { begin, end }; - range.add_base_address(self.base_address, self.raw.encoding.address_size); - (range, data) - } - RawLocListEntry::StartEnd { begin, end, data } => (Range { begin, end }, data), - RawLocListEntry::StartLength { - begin, - length, - data, - } => { - let end = begin.wrapping_add(length) & mask; - (Range { begin, end }, data) - } - }; - - if range.begin == tombstone { - return Ok(None); - } - - if range.begin > range.end { - self.raw.input.empty(); - return Err(Error::InvalidLocationAddressRange); - } - - Ok(Some(LocationListEntry { range, data })) - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for LocListIter<R> { - type Item = LocationListEntry<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - LocListIter::next(self) - } -} - -/// A location list entry from the `.debug_loc` or `.debug_loclists` sections. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct LocationListEntry<R: Reader> { - /// The address range that this location is valid for. - pub range: Range, - - /// The data containing a single location description. - pub data: Expression<R>, -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::common::Format; - use crate::endianity::LittleEndian; - use crate::read::{EndianSlice, Range}; - use crate::test_util::GimliSectionMethods; - use test_assembler::{Endian, Label, LabelMaker, Section}; - - #[test] - fn test_loclists_32() { - let tombstone = !0u32; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - - let section = Section::with_endian(Endian::Little) - .L32(0x0300_0000) - .L32(0x0301_0300) - .L32(0x0301_0400) - .L32(0x0301_0500) - .L32(tombstone) - .L32(0x0301_0600); - let buf = section.get_contents().unwrap(); - let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - - let start = Label::new(); - let first = Label::new(); - let size = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // Header - .mark(&start) - .L32(&size) - .L16(encoding.version) - .L8(encoding.address_size) - .L8(0) - .L32(0) - .mark(&first) - // OffsetPair - .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2) - // A base address selection followed by an OffsetPair. - .L8(6).L32(0x0200_0000) - .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3) - // An empty OffsetPair followed by a normal OffsetPair. - .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4) - .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5) - // A StartEnd - .L8(7).L32(0x201_0a00).L32(0x201_0b00).uleb(4).L32(6) - // A StartLength - .L8(8).L32(0x201_0c00).uleb(0x100).uleb(4).L32(7) - // An OffsetPair that starts at 0. - .L8(4).uleb(0).uleb(1).uleb(4).L32(8) - // An OffsetPair that ends at -1. - .L8(6).L32(0) - .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9) - // A DefaultLocation - .L8(5).uleb(4).L32(10) - // A BaseAddressx + OffsetPair - .L8(1).uleb(0) - .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11) - // A StartxEndx - .L8(2).uleb(1).uleb(2).uleb(4).L32(12) - // A StartxLength - .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13) - - // Tombstone entries, all of which should be ignored. - // A BaseAddressx that is a tombstone. - .L8(1).uleb(4) - .L8(4).uleb(0x11100).uleb(0x11200).uleb(4).L32(20) - // A BaseAddress that is a tombstone. - .L8(6).L32(tombstone) - .L8(4).uleb(0x11300).uleb(0x11400).uleb(4).L32(21) - // A StartxEndx that is a tombstone. - .L8(2).uleb(4).uleb(5).uleb(4).L32(22) - // A StartxLength that is a tombstone. - .L8(3).uleb(4).uleb(0x100).uleb(4).L32(23) - // A StartEnd that is a tombstone. - .L8(7).L32(tombstone).L32(0x201_1500).uleb(4).L32(24) - // A StartLength that is a tombstone. - .L8(8).L32(tombstone).uleb(0x100).uleb(4).L32(25) - // A StartEnd (not ignored) - .L8(7).L32(0x201_1600).L32(0x201_1700).uleb(4).L32(26) - - // A range end. - .L8(0) - // Some extra data. - .L32(0xffff_ffff); - size.set_const((§ion.here() - &start - 4) as u64); - - let buf = section.get_contents().unwrap(); - let debug_loc = DebugLoc::new(&[], LittleEndian); - let debug_loclists = DebugLocLists::new(&buf, LittleEndian); - let loclists = LocationLists::new(debug_loc, debug_loclists); - let offset = LocationListsOffset((&first - &start) as usize); - let mut locations = loclists - .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) - .unwrap(); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0101_0200, - end: 0x0101_0300, - }, - data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)), - })) - ); - - // A base address selection followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0400, - end: 0x0201_0500, - }, - data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)), - })) - ); - - // An empty location range followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0600, - end: 0x0201_0600, - }, - data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)), - })) - ); - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0800, - end: 0x0201_0900, - }, - data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)), - })) - ); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0a00, - end: 0x0201_0b00, - }, - data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)), - })) - ); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0c00, - end: 0x0201_0d00, - }, - data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that starts at 0. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0200_0000, - end: 0x0200_0001, - }, - data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that ends at -1. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0000_0000, - end: 0xffff_ffff, - }, - data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)), - })) - ); - - // A DefaultLocation. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0, - end: u64::max_value(), - }, - data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)), - })) - ); - - // A BaseAddressx + OffsetPair - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0301_0100, - end: 0x0301_0200, - }, - data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)), - })) - ); - - // A StartxEndx - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0301_0300, - end: 0x0301_0400, - }, - data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)), - })) - ); - - // A StartxLength - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0301_0500, - end: 0x0301_0600, - }, - data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)), - })) - ); - - // A StartEnd location following the tombstones - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_1600, - end: 0x0201_1700, - }, - data: Expression(EndianSlice::new(&[26, 0, 0, 0], LittleEndian)), - })) - ); - - // A location list end. - assert_eq!(locations.next(), Ok(None)); - - // An offset at the end of buf. - let mut locations = loclists - .locations( - LocationListsOffset(buf.len()), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(locations.next(), Ok(None)); - } - - #[test] - fn test_loclists_64() { - let tombstone = !0u64; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - - let section = Section::with_endian(Endian::Little) - .L64(0x0300_0000) - .L64(0x0301_0300) - .L64(0x0301_0400) - .L64(0x0301_0500) - .L64(tombstone) - .L64(0x0301_0600); - let buf = section.get_contents().unwrap(); - let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - - let start = Label::new(); - let first = Label::new(); - let size = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // Header - .mark(&start) - .L32(0xffff_ffff) - .L64(&size) - .L16(encoding.version) - .L8(encoding.address_size) - .L8(0) - .L32(0) - .mark(&first) - // OffsetPair - .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2) - // A base address selection followed by an OffsetPair. - .L8(6).L64(0x0200_0000) - .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3) - // An empty OffsetPair followed by a normal OffsetPair. - .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4) - .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5) - // A StartEnd - .L8(7).L64(0x201_0a00).L64(0x201_0b00).uleb(4).L32(6) - // A StartLength - .L8(8).L64(0x201_0c00).uleb(0x100).uleb(4).L32(7) - // An OffsetPair that starts at 0. - .L8(4).uleb(0).uleb(1).uleb(4).L32(8) - // An OffsetPair that ends at -1. - .L8(6).L64(0) - .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9) - // A DefaultLocation - .L8(5).uleb(4).L32(10) - // A BaseAddressx + OffsetPair - .L8(1).uleb(0) - .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11) - // A StartxEndx - .L8(2).uleb(1).uleb(2).uleb(4).L32(12) - // A StartxLength - .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13) - - // Tombstone entries, all of which should be ignored. - // A BaseAddressx that is a tombstone. - .L8(1).uleb(4) - .L8(4).uleb(0x11100).uleb(0x11200).uleb(4).L32(20) - // A BaseAddress that is a tombstone. - .L8(6).L64(tombstone) - .L8(4).uleb(0x11300).uleb(0x11400).uleb(4).L32(21) - // A StartxEndx that is a tombstone. - .L8(2).uleb(4).uleb(5).uleb(4).L32(22) - // A StartxLength that is a tombstone. - .L8(3).uleb(4).uleb(0x100).uleb(4).L32(23) - // A StartEnd that is a tombstone. - .L8(7).L64(tombstone).L64(0x201_1500).uleb(4).L32(24) - // A StartLength that is a tombstone. - .L8(8).L64(tombstone).uleb(0x100).uleb(4).L32(25) - // A StartEnd (not ignored) - .L8(7).L64(0x201_1600).L64(0x201_1700).uleb(4).L32(26) - - // A range end. - .L8(0) - // Some extra data. - .L32(0xffff_ffff); - size.set_const((§ion.here() - &start - 12) as u64); - - let buf = section.get_contents().unwrap(); - let debug_loc = DebugLoc::new(&[], LittleEndian); - let debug_loclists = DebugLocLists::new(&buf, LittleEndian); - let loclists = LocationLists::new(debug_loc, debug_loclists); - let offset = LocationListsOffset((&first - &start) as usize); - let mut locations = loclists - .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) - .unwrap(); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0101_0200, - end: 0x0101_0300, - }, - data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)), - })) - ); - - // A base address selection followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0400, - end: 0x0201_0500, - }, - data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)), - })) - ); - - // An empty location range followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0600, - end: 0x0201_0600, - }, - data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)), - })) - ); - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0800, - end: 0x0201_0900, - }, - data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)), - })) - ); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0a00, - end: 0x0201_0b00, - }, - data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)), - })) - ); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0c00, - end: 0x0201_0d00, - }, - data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that starts at 0. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0200_0000, - end: 0x0200_0001, - }, - data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that ends at -1. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0000_0000, - end: 0xffff_ffff, - }, - data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)), - })) - ); - - // A DefaultLocation. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0, - end: u64::max_value(), - }, - data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)), - })) - ); - - // A BaseAddressx + OffsetPair - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0301_0100, - end: 0x0301_0200, - }, - data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)), - })) - ); - - // A StartxEndx - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0301_0300, - end: 0x0301_0400, - }, - data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)), - })) - ); - - // A StartxLength - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0301_0500, - end: 0x0301_0600, - }, - data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)), - })) - ); - - // A StartEnd location following the tombstones - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_1600, - end: 0x0201_1700, - }, - data: Expression(EndianSlice::new(&[26, 0, 0, 0], LittleEndian)), - })) - ); - - // A location list end. - assert_eq!(locations.next(), Ok(None)); - - // An offset at the end of buf. - let mut locations = loclists - .locations( - LocationListsOffset(buf.len()), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(locations.next(), Ok(None)); - } - - #[test] - fn test_location_list_32() { - let tombstone = !0u32 - 1; - let start = Label::new(); - let first = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // A location before the offset. - .mark(&start) - .L32(0x10000).L32(0x10100).L16(4).L32(1) - .mark(&first) - // A normal location. - .L32(0x10200).L32(0x10300).L16(4).L32(2) - // A base address selection followed by a normal location. - .L32(0xffff_ffff).L32(0x0200_0000) - .L32(0x10400).L32(0x10500).L16(4).L32(3) - // An empty location range followed by a normal location. - .L32(0x10600).L32(0x10600).L16(4).L32(4) - .L32(0x10800).L32(0x10900).L16(4).L32(5) - // A location range that starts at 0. - .L32(0).L32(1).L16(4).L32(6) - // A location range that ends at -1. - .L32(0xffff_ffff).L32(0x0000_0000) - .L32(0).L32(0xffff_ffff).L16(4).L32(7) - // A normal location with tombstone. - .L32(tombstone).L32(tombstone).L16(4).L32(8) - // A base address selection with tombstone followed by a normal location. - .L32(0xffff_ffff).L32(tombstone) - .L32(0x10a00).L32(0x10b00).L16(4).L32(9) - // A location list end. - .L32(0).L32(0) - // Some extra data. - .L32(0); - - let buf = section.get_contents().unwrap(); - let debug_loc = DebugLoc::new(&buf, LittleEndian); - let debug_loclists = DebugLocLists::new(&[], LittleEndian); - let loclists = LocationLists::new(debug_loc, debug_loclists); - let offset = LocationListsOffset((&first - &start) as usize); - let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut locations = loclists - .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) - .unwrap(); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0101_0200, - end: 0x0101_0300, - }, - data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)), - })) - ); - - // A base address selection followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0400, - end: 0x0201_0500, - }, - data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)), - })) - ); - - // An empty location range followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0600, - end: 0x0201_0600, - }, - data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)), - })) - ); - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0800, - end: 0x0201_0900, - }, - data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that starts at 0. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0200_0000, - end: 0x0200_0001, - }, - data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that ends at -1. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0000_0000, - end: 0xffff_ffff, - }, - data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)), - })) - ); - - // A location list end. - assert_eq!(locations.next(), Ok(None)); - - // An offset at the end of buf. - let mut locations = loclists - .locations( - LocationListsOffset(buf.len()), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(locations.next(), Ok(None)); - } - - #[test] - fn test_location_list_64() { - let tombstone = !0u64 - 1; - let start = Label::new(); - let first = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // A location before the offset. - .mark(&start) - .L64(0x10000).L64(0x10100).L16(4).L32(1) - .mark(&first) - // A normal location. - .L64(0x10200).L64(0x10300).L16(4).L32(2) - // A base address selection followed by a normal location. - .L64(0xffff_ffff_ffff_ffff).L64(0x0200_0000) - .L64(0x10400).L64(0x10500).L16(4).L32(3) - // An empty location range followed by a normal location. - .L64(0x10600).L64(0x10600).L16(4).L32(4) - .L64(0x10800).L64(0x10900).L16(4).L32(5) - // A location range that starts at 0. - .L64(0).L64(1).L16(4).L32(6) - // A location range that ends at -1. - .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000) - .L64(0).L64(0xffff_ffff_ffff_ffff).L16(4).L32(7) - // A normal location with tombstone. - .L64(tombstone).L64(tombstone).L16(4).L32(8) - // A base address selection with tombstone followed by a normal location. - .L64(0xffff_ffff_ffff_ffff).L64(tombstone) - .L64(0x10a00).L64(0x10b00).L16(4).L32(9) - // A location list end. - .L64(0).L64(0) - // Some extra data. - .L64(0); - - let buf = section.get_contents().unwrap(); - let debug_loc = DebugLoc::new(&buf, LittleEndian); - let debug_loclists = DebugLocLists::new(&[], LittleEndian); - let loclists = LocationLists::new(debug_loc, debug_loclists); - let offset = LocationListsOffset((&first - &start) as usize); - let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - let encoding = Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }; - let mut locations = loclists - .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) - .unwrap(); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0101_0200, - end: 0x0101_0300, - }, - data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)), - })) - ); - - // A base address selection followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0400, - end: 0x0201_0500, - }, - data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)), - })) - ); - - // An empty location range followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0600, - end: 0x0201_0600, - }, - data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)), - })) - ); - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0201_0800, - end: 0x0201_0900, - }, - data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that starts at 0. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0200_0000, - end: 0x0200_0001, - }, - data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that ends at -1. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0, - end: 0xffff_ffff_ffff_ffff, - }, - data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)), - })) - ); - - // A location list end. - assert_eq!(locations.next(), Ok(None)); - - // An offset at the end of buf. - let mut locations = loclists - .locations( - LocationListsOffset(buf.len()), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(locations.next(), Ok(None)); - } - - #[test] - fn test_locations_invalid() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // An invalid location range. - .L32(0x20000).L32(0x10000).L16(4).L32(1) - // An invalid range after wrapping. - .L32(0x20000).L32(0xff01_0000).L16(4).L32(2); - - let buf = section.get_contents().unwrap(); - let debug_loc = DebugLoc::new(&buf, LittleEndian); - let debug_loclists = DebugLocLists::new(&[], LittleEndian); - let loclists = LocationLists::new(debug_loc, debug_loclists); - let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - - // An invalid location range. - let mut locations = loclists - .locations( - LocationListsOffset(0x0), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); - - // An invalid location range after wrapping. - let mut locations = loclists - .locations( - LocationListsOffset(14), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); - - // An invalid offset. - match loclists.locations( - LocationListsOffset(buf.len() + 1), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) { - Err(Error::UnexpectedEof(_)) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - fn test_get_offset() { - for format in vec![Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version: 5, - address_size: 4, - }; - - let zero = Label::new(); - let length = Label::new(); - let start = Label::new(); - let first = Label::new(); - let end = Label::new(); - let mut section = Section::with_endian(Endian::Little) - .mark(&zero) - .initial_length(format, &length, &start) - .D16(encoding.version) - .D8(encoding.address_size) - .D8(0) - .D32(20) - .mark(&first); - for i in 0..20 { - section = section.word(format.word_size(), 1000 + i); - } - section = section.mark(&end); - length.set_const((&end - &start) as u64); - let section = section.get_contents().unwrap(); - - let debug_loc = DebugLoc::from(EndianSlice::new(&[], LittleEndian)); - let debug_loclists = DebugLocLists::from(EndianSlice::new(§ion, LittleEndian)); - let locations = LocationLists::new(debug_loc, debug_loclists); - - let base = DebugLocListsBase((&first - &zero) as usize); - assert_eq!( - locations.get_offset(encoding, base, DebugLocListsIndex(0)), - Ok(LocationListsOffset(base.0 + 1000)) - ); - assert_eq!( - locations.get_offset(encoding, base, DebugLocListsIndex(19)), - Ok(LocationListsOffset(base.0 + 1019)) - ); - } - } - - #[test] - fn test_loclists_gnu_v4_split_dwarf() { - #[rustfmt::skip] - let buf = [ - 0x03, // DW_LLE_startx_length - 0x00, // ULEB encoded b7 - 0x08, 0x00, 0x00, 0x00, // Fixed 4 byte length of 8 - 0x03, 0x00, // Fixed two byte length of the location - 0x11, 0x00, // DW_OP_constu 0 - 0x9f, // DW_OP_stack_value - // Padding data - //0x99, 0x99, 0x99, 0x99 - ]; - let data_buf = [0x11, 0x00, 0x9f]; - let expected_data = EndianSlice::new(&data_buf, LittleEndian); - let debug_loc = DebugLoc::new(&buf, LittleEndian); - let debug_loclists = DebugLocLists::new(&[], LittleEndian); - let loclists = LocationLists::new(debug_loc, debug_loclists); - let debug_addr = - &DebugAddr::from(EndianSlice::new(&[0x01, 0x02, 0x03, 0x04], LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - - // An invalid location range. - let mut locations = loclists - .locations_dwo( - LocationListsOffset(0x0), - encoding, - 0, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0403_0201, - end: 0x0403_0209 - }, - data: Expression(expected_data), - })) - ); - } -} diff --git a/vendor/gimli/src/read/lookup.rs b/vendor/gimli/src/read/lookup.rs deleted file mode 100644 index 1d082f2..0000000 --- a/vendor/gimli/src/read/lookup.rs +++ /dev/null @@ -1,202 +0,0 @@ -use core::marker::PhantomData; - -use crate::common::{DebugInfoOffset, Format}; -use crate::read::{parse_debug_info_offset, Error, Reader, ReaderOffset, Result, UnitOffset}; - -// The various "Accelerated Access" sections (DWARF standard v4 Section 6.1) all have -// similar structures. They consist of a header with metadata and an offset into the -// .debug_info section for the entire compilation unit, and a series -// of following entries that list addresses (for .debug_aranges) or names -// (for .debug_pubnames and .debug_pubtypes) that are covered. -// -// Because these three tables all have similar structures, we abstract out some of -// the parsing mechanics. - -pub trait LookupParser<R: Reader> { - /// The type of the produced header. - type Header; - /// The type of the produced entry. - type Entry; - - /// Parse a header from `input`. Returns a tuple of `input` sliced to contain just the entries - /// corresponding to this header (without the header itself), and the parsed representation of - /// the header itself. - fn parse_header(input: &mut R) -> Result<(R, Self::Header)>; - - /// Parse a single entry from `input`. Returns either a parsed representation of the entry - /// or None if `input` is exhausted. - fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>>; -} - -#[derive(Clone, Debug)] -pub struct DebugLookup<R, Parser> -where - R: Reader, - Parser: LookupParser<R>, -{ - input_buffer: R, - phantom: PhantomData<Parser>, -} - -impl<R, Parser> From<R> for DebugLookup<R, Parser> -where - R: Reader, - Parser: LookupParser<R>, -{ - fn from(input_buffer: R) -> Self { - DebugLookup { - input_buffer, - phantom: PhantomData, - } - } -} - -impl<R, Parser> DebugLookup<R, Parser> -where - R: Reader, - Parser: LookupParser<R>, -{ - pub fn items(&self) -> LookupEntryIter<R, Parser> { - LookupEntryIter { - current_set: None, - remaining_input: self.input_buffer.clone(), - } - } - - pub fn reader(&self) -> &R { - &self.input_buffer - } -} - -#[derive(Clone, Debug)] -pub struct LookupEntryIter<R, Parser> -where - R: Reader, - Parser: LookupParser<R>, -{ - current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end. - remaining_input: R, -} - -impl<R, Parser> LookupEntryIter<R, Parser> -where - R: Reader, - Parser: LookupParser<R>, -{ - /// Advance the iterator and return the next entry. - /// - /// Returns the newly parsed entry as `Ok(Some(Parser::Entry))`. Returns - /// `Ok(None)` when iteration is complete and all entries have already been - /// parsed and yielded. If an error occurs while parsing the next entry, - /// then this error is returned as `Err(e)`, and all subsequent calls return - /// `Ok(None)`. - /// - /// Can be [used with `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn next(&mut self) -> Result<Option<Parser::Entry>> { - loop { - if let Some((ref mut input, ref header)) = self.current_set { - if !input.is_empty() { - match Parser::parse_entry(input, header) { - Ok(Some(entry)) => return Ok(Some(entry)), - Ok(None) => {} - Err(e) => { - input.empty(); - self.remaining_input.empty(); - return Err(e); - } - } - } - } - if self.remaining_input.is_empty() { - self.current_set = None; - return Ok(None); - } - match Parser::parse_header(&mut self.remaining_input) { - Ok(set) => { - self.current_set = Some(set); - } - Err(e) => { - self.current_set = None; - self.remaining_input.empty(); - return Err(e); - } - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PubStuffHeader<T = usize> { - format: Format, - length: T, - version: u16, - unit_offset: DebugInfoOffset<T>, - unit_length: T, -} - -pub trait PubStuffEntry<R: Reader> { - fn new( - die_offset: UnitOffset<R::Offset>, - name: R, - unit_header_offset: DebugInfoOffset<R::Offset>, - ) -> Self; -} - -#[derive(Clone, Debug)] -pub struct PubStuffParser<R, Entry> -where - R: Reader, - Entry: PubStuffEntry<R>, -{ - // This struct is never instantiated. - phantom: PhantomData<(R, Entry)>, -} - -impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry> -where - R: Reader, - Entry: PubStuffEntry<R>, -{ - type Header = PubStuffHeader<R::Offset>; - type Entry = Entry; - - /// Parse an pubthings set header. Returns a tuple of the - /// pubthings to be parsed for this set, and the newly created PubThingHeader struct. - fn parse_header(input: &mut R) -> Result<(R, Self::Header)> { - let (length, format) = input.read_initial_length()?; - let mut rest = input.split(length)?; - - let version = rest.read_u16()?; - if version != 2 { - return Err(Error::UnknownVersion(u64::from(version))); - } - - let unit_offset = parse_debug_info_offset(&mut rest, format)?; - let unit_length = rest.read_length(format)?; - - let header = PubStuffHeader { - format, - length, - version, - unit_offset, - unit_length, - }; - Ok((rest, header)) - } - - /// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing. - fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> { - let offset = input.read_offset(header.format)?; - if offset.into_u64() == 0 { - input.empty(); - Ok(None) - } else { - let name = input.read_null_terminated_slice()?; - Ok(Some(Self::Entry::new( - UnitOffset(offset), - name, - header.unit_offset, - ))) - } - } -} diff --git a/vendor/gimli/src/read/mod.rs b/vendor/gimli/src/read/mod.rs deleted file mode 100644 index 2ad7f6a..0000000 --- a/vendor/gimli/src/read/mod.rs +++ /dev/null @@ -1,827 +0,0 @@ -//! Read DWARF debugging information. -//! -//! * [Example Usage](#example-usage) -//! * [API Structure](#api-structure) -//! * [Using with `FallibleIterator`](#using-with-fallibleiterator) -//! -//! ## Example Usage -//! -//! Print out all of the functions in the debuggee program: -//! -//! ```rust,no_run -//! # fn example() -> Result<(), gimli::Error> { -//! # type R = gimli::EndianSlice<'static, gimli::LittleEndian>; -//! # let get_file_section_reader = |name| -> Result<R, gimli::Error> { unimplemented!() }; -//! # let get_sup_file_section_reader = |name| -> Result<R, gimli::Error> { unimplemented!() }; -//! // Read the DWARF sections with whatever object loader you're using. -//! // These closures should return a `Reader` instance (e.g. `EndianSlice`). -//! let loader = |section: gimli::SectionId| { get_file_section_reader(section.name()) }; -//! let sup_loader = |section: gimli::SectionId| { get_sup_file_section_reader(section.name()) }; -//! let mut dwarf = gimli::Dwarf::load(loader)?; -//! dwarf.load_sup(sup_loader)?; -//! -//! // Iterate over all compilation units. -//! let mut iter = dwarf.units(); -//! while let Some(header) = iter.next()? { -//! // Parse the abbreviations and other information for this compilation unit. -//! let unit = dwarf.unit(header)?; -//! -//! // Iterate over all of this compilation unit's entries. -//! let mut entries = unit.entries(); -//! while let Some((_, entry)) = entries.next_dfs()? { -//! // If we find an entry for a function, print it. -//! if entry.tag() == gimli::DW_TAG_subprogram { -//! println!("Found a function: {:?}", entry); -//! } -//! } -//! } -//! # unreachable!() -//! # } -//! ``` -//! -//! Full example programs: -//! -//! * [A simple parser](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/simple.rs) -//! -//! * [A `dwarfdump` -//! clone](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/dwarfdump.rs) -//! -//! * [An `addr2line` clone](https://github.com/gimli-rs/addr2line) -//! -//! * [`ddbug`](https://github.com/gimli-rs/ddbug), a utility giving insight into -//! code generation by making debugging information readable -//! -//! * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the -//! compilers used to create each compilation unit within a shared library or -//! executable (via `DW_AT_producer`) -//! -//! * [`dwarf-validate`](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/dwarf-validate.rs), -//! a program to validate the integrity of some DWARF and its references -//! between sections and compilation units. -//! -//! ## API Structure -//! -//! * Basic familiarity with DWARF is assumed. -//! -//! * The [`Dwarf`](./struct.Dwarf.html) type contains the commonly used DWARF -//! sections. It has methods that simplify access to debugging data that spans -//! multiple sections. Use of this type is optional, but recommended. -//! -//! * Each section gets its own type. Consider these types the entry points to -//! the library: -//! -//! * [`DebugAbbrev`](./struct.DebugAbbrev.html): The `.debug_abbrev` section. -//! -//! * [`DebugAddr`](./struct.DebugAddr.html): The `.debug_addr` section. -//! -//! * [`DebugAranges`](./struct.DebugAranges.html): The `.debug_aranges` -//! section. -//! -//! * [`DebugFrame`](./struct.DebugFrame.html): The `.debug_frame` section. -//! -//! * [`DebugInfo`](./struct.DebugInfo.html): The `.debug_info` section. -//! -//! * [`DebugLine`](./struct.DebugLine.html): The `.debug_line` section. -//! -//! * [`DebugLineStr`](./struct.DebugLineStr.html): The `.debug_line_str` section. -//! -//! * [`DebugLoc`](./struct.DebugLoc.html): The `.debug_loc` section. -//! -//! * [`DebugLocLists`](./struct.DebugLocLists.html): The `.debug_loclists` section. -//! -//! * [`DebugPubNames`](./struct.DebugPubNames.html): The `.debug_pubnames` -//! section. -//! -//! * [`DebugPubTypes`](./struct.DebugPubTypes.html): The `.debug_pubtypes` -//! section. -//! -//! * [`DebugRanges`](./struct.DebugRanges.html): The `.debug_ranges` section. -//! -//! * [`DebugRngLists`](./struct.DebugRngLists.html): The `.debug_rnglists` section. -//! -//! * [`DebugStr`](./struct.DebugStr.html): The `.debug_str` section. -//! -//! * [`DebugStrOffsets`](./struct.DebugStrOffsets.html): The `.debug_str_offsets` section. -//! -//! * [`DebugTypes`](./struct.DebugTypes.html): The `.debug_types` section. -//! -//! * [`DebugCuIndex`](./struct.DebugCuIndex.html): The `.debug_cu_index` section. -//! -//! * [`DebugTuIndex`](./struct.DebugTuIndex.html): The `.debug_tu_index` section. -//! -//! * [`EhFrame`](./struct.EhFrame.html): The `.eh_frame` section. -//! -//! * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section. -//! -//! * Each section type exposes methods for accessing the debugging data encoded -//! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html) -//! struct has the [`units`](./struct.DebugInfo.html#method.units) method for -//! iterating over the compilation units defined within it. -//! -//! * Offsets into a section are strongly typed: an offset into `.debug_info` is -//! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be -//! used to index into the [`DebugLine`](./struct.DebugLine.html) type because -//! `DebugLine` represents the `.debug_line` section. There are similar types -//! for offsets relative to a compilation unit rather than a section. -//! -//! ## Using with `FallibleIterator` -//! -//! The standard library's `Iterator` trait and related APIs do not play well -//! with iterators where the `next` operation is fallible. One can make the -//! `Iterator`'s associated `Item` type be a `Result<T, E>`, however the -//! provided methods cannot gracefully handle the case when an `Err` is -//! returned. -//! -//! This situation led to the -//! [`fallible-iterator`](https://crates.io/crates/fallible-iterator) crate's -//! existence. You can read more of the rationale for its existence in its -//! docs. The crate provides the helpers you have come to expect (eg `map`, -//! `filter`, etc) for iterators that can fail. -//! -//! `gimli`'s many lazy parsing iterators are a perfect match for the -//! `fallible-iterator` crate's `FallibleIterator` trait because parsing is not -//! done eagerly. Parse errors later in the input might only be discovered after -//! having iterated through many items. -//! -//! To use `gimli` iterators with `FallibleIterator`, import the crate and trait -//! into your code: -//! -//! ``` -//! # #[cfg(feature = "fallible-iterator")] -//! # fn foo() { -//! // Use the `FallibleIterator` trait so its methods are in scope! -//! use fallible_iterator::FallibleIterator; -//! use gimli::{DebugAranges, EndianSlice, LittleEndian}; -//! -//! fn find_sum_of_address_range_lengths(aranges: DebugAranges<EndianSlice<LittleEndian>>) -//! -> gimli::Result<u64> -//! { -//! // `DebugAranges::headers` returns a `FallibleIterator`! -//! aranges.headers() -//! // `flat_map` is provided by `FallibleIterator`! -//! .flat_map(|header| Ok(header.entries())) -//! // `map` is provided by `FallibleIterator`! -//! .map(|arange| Ok(arange.length())) -//! // `fold` is provided by `FallibleIterator`! -//! .fold(0, |sum, len| Ok(sum + len)) -//! } -//! # } -//! # fn main() {} -//! ``` - -use core::fmt::{self, Debug}; -use core::result; -#[cfg(feature = "std")] -use std::{error, io}; - -use crate::common::{Register, SectionId}; -use crate::constants; - -mod util; -pub use util::*; - -mod addr; -pub use self::addr::*; - -mod cfi; -pub use self::cfi::*; - -#[cfg(feature = "read")] -mod dwarf; -#[cfg(feature = "read")] -pub use self::dwarf::*; - -mod endian_slice; -pub use self::endian_slice::*; - -#[cfg(feature = "endian-reader")] -mod endian_reader; -#[cfg(feature = "endian-reader")] -pub use self::endian_reader::*; - -mod reader; -pub use self::reader::*; - -#[cfg(feature = "read")] -mod abbrev; -#[cfg(feature = "read")] -pub use self::abbrev::*; - -mod aranges; -pub use self::aranges::*; - -mod index; -pub use self::index::*; - -#[cfg(feature = "read")] -mod line; -#[cfg(feature = "read")] -pub use self::line::*; - -mod lists; - -mod loclists; -pub use self::loclists::*; - -#[cfg(feature = "read")] -mod lookup; - -mod op; -pub use self::op::*; - -#[cfg(feature = "read")] -mod pubnames; -#[cfg(feature = "read")] -pub use self::pubnames::*; - -#[cfg(feature = "read")] -mod pubtypes; -#[cfg(feature = "read")] -pub use self::pubtypes::*; - -mod rnglists; -pub use self::rnglists::*; - -mod str; -pub use self::str::*; - -/// An offset into the current compilation or type unit. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] -pub struct UnitOffset<T = usize>(pub T); - -#[cfg(feature = "read")] -mod unit; -#[cfg(feature = "read")] -pub use self::unit::*; - -mod value; -pub use self::value::*; - -/// Indicates that storage should be allocated on heap. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct StoreOnHeap; - -/// `EndianBuf` has been renamed to `EndianSlice`. For ease of upgrading across -/// `gimli` versions, we export this type alias. -#[deprecated(note = "EndianBuf has been renamed to EndianSlice, use that instead.")] -pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>; - -/// An error that occurred when parsing. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Error { - /// An I/O error occurred while reading. - Io, - /// Found a PC relative pointer, but the section base is undefined. - PcRelativePointerButSectionBaseIsUndefined, - /// Found a `.text` relative pointer, but the `.text` base is undefined. - TextRelativePointerButTextBaseIsUndefined, - /// Found a data relative pointer, but the data base is undefined. - DataRelativePointerButDataBaseIsUndefined, - /// Found a function relative pointer in a context that does not have a - /// function base. - FuncRelativePointerInBadContext, - /// Cannot parse a pointer with a `DW_EH_PE_omit` encoding. - CannotParseOmitPointerEncoding, - /// An error parsing an unsigned LEB128 value. - BadUnsignedLeb128, - /// An error parsing a signed LEB128 value. - BadSignedLeb128, - /// An abbreviation declared that its tag is zero, but zero is reserved for - /// null records. - AbbreviationTagZero, - /// An attribute specification declared that its form is zero, but zero is - /// reserved for null records. - AttributeFormZero, - /// The abbreviation's has-children byte was not one of - /// `DW_CHILDREN_{yes,no}`. - BadHasChildren, - /// The specified length is impossible. - BadLength, - /// Found an unknown `DW_FORM_*` type. - UnknownForm, - /// Expected a zero, found something else. - ExpectedZero, - /// Found an abbreviation code that has already been used. - DuplicateAbbreviationCode, - /// Found a duplicate arange. - DuplicateArange, - /// Found an unknown reserved length value. - UnknownReservedLength, - /// Found an unknown DWARF version. - UnknownVersion(u64), - /// Found a record with an unknown abbreviation code. - UnknownAbbreviation, - /// Hit the end of input before it was expected. - UnexpectedEof(ReaderOffsetId), - /// Read a null entry before it was expected. - UnexpectedNull, - /// Found an unknown standard opcode. - UnknownStandardOpcode(constants::DwLns), - /// Found an unknown extended opcode. - UnknownExtendedOpcode(constants::DwLne), - /// The specified address size is not supported. - UnsupportedAddressSize(u8), - /// The specified offset size is not supported. - UnsupportedOffsetSize(u8), - /// The specified field size is not supported. - UnsupportedFieldSize(u8), - /// The minimum instruction length must not be zero. - MinimumInstructionLengthZero, - /// The maximum operations per instruction must not be zero. - MaximumOperationsPerInstructionZero, - /// The line range must not be zero. - LineRangeZero, - /// The opcode base must not be zero. - OpcodeBaseZero, - /// Found an invalid UTF-8 string. - BadUtf8, - /// Expected to find the CIE ID, but found something else. - NotCieId, - /// Expected to find a pointer to a CIE, but found the CIE ID instead. - NotCiePointer, - /// Expected to find a pointer to an FDE, but found a CIE instead. - NotFdePointer, - /// Invalid branch target for a DW_OP_bra or DW_OP_skip. - BadBranchTarget(u64), - /// DW_OP_push_object_address used but no address passed in. - InvalidPushObjectAddress, - /// Not enough items on the stack when evaluating an expression. - NotEnoughStackItems, - /// Too many iterations to compute the expression. - TooManyIterations, - /// An unrecognized operation was found while parsing a DWARF - /// expression. - InvalidExpression(constants::DwOp), - /// An unsupported operation was found while evaluating a DWARF expression. - UnsupportedEvaluation, - /// The expression had a piece followed by an expression - /// terminator without a piece. - InvalidPiece, - /// An expression-terminating operation was followed by something - /// other than the end of the expression or a piece operation. - InvalidExpressionTerminator(u64), - /// Division or modulus by zero when evaluating an expression. - DivisionByZero, - /// An expression operation used mismatching types. - TypeMismatch, - /// An expression operation required an integral type but saw a - /// floating point type. - IntegralTypeRequired, - /// An expression operation used types that are not supported. - UnsupportedTypeOperation, - /// The shift value in an expression must be a non-negative integer. - InvalidShiftExpression, - /// An unknown DW_CFA_* instruction. - UnknownCallFrameInstruction(constants::DwCfa), - /// The end of an address range was before the beginning. - InvalidAddressRange, - /// The end offset of a loc list entry was before the beginning. - InvalidLocationAddressRange, - /// Encountered a call frame instruction in a context in which it is not - /// valid. - CfiInstructionInInvalidContext, - /// When evaluating call frame instructions, found a `DW_CFA_restore_state` - /// stack pop instruction, but the stack was empty, and had nothing to pop. - PopWithEmptyStack, - /// Do not have unwind info for the given address. - NoUnwindInfoForAddress, - /// An offset value was larger than the maximum supported value. - UnsupportedOffset, - /// The given pointer encoding is either unknown or invalid. - UnknownPointerEncoding, - /// Did not find an entry at the given offset. - NoEntryAtGivenOffset, - /// The given offset is out of bounds. - OffsetOutOfBounds, - /// Found an unknown CFI augmentation. - UnknownAugmentation, - /// We do not support the given pointer encoding yet. - UnsupportedPointerEncoding, - /// Registers larger than `u16` are not supported. - UnsupportedRegister(u64), - /// The CFI program defined more register rules than we have storage for. - TooManyRegisterRules, - /// Attempted to push onto the CFI or evaluation stack, but it was already - /// at full capacity. - StackFull, - /// The `.eh_frame_hdr` binary search table claims to be variable-length encoded, - /// which makes binary search impossible. - VariableLengthSearchTable, - /// The `DW_UT_*` value for this unit is not supported yet. - UnsupportedUnitType, - /// Ranges using AddressIndex are not supported yet. - UnsupportedAddressIndex, - /// Nonzero segment selector sizes aren't supported yet. - UnsupportedSegmentSize, - /// A compilation unit or type unit is missing its top level DIE. - MissingUnitDie, - /// A DIE attribute used an unsupported form. - UnsupportedAttributeForm, - /// Missing DW_LNCT_path in file entry format. - MissingFileEntryFormatPath, - /// Expected an attribute value to be a string form. - ExpectedStringAttributeValue, - /// `DW_FORM_implicit_const` used in an invalid context. - InvalidImplicitConst, - /// Invalid section count in `.dwp` index. - InvalidIndexSectionCount, - /// Invalid slot count in `.dwp` index. - InvalidIndexSlotCount, - /// Invalid hash row in `.dwp` index. - InvalidIndexRow, - /// Unknown section type in `.dwp` index. - UnknownIndexSection, -} - -impl fmt::Display for Error { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error> { - write!(f, "{}", self.description()) - } -} - -impl Error { - /// A short description of the error. - pub fn description(&self) -> &str { - match *self { - Error::Io => "An I/O error occurred while reading.", - Error::PcRelativePointerButSectionBaseIsUndefined => { - "Found a PC relative pointer, but the section base is undefined." - } - Error::TextRelativePointerButTextBaseIsUndefined => { - "Found a `.text` relative pointer, but the `.text` base is undefined." - } - Error::DataRelativePointerButDataBaseIsUndefined => { - "Found a data relative pointer, but the data base is undefined." - } - Error::FuncRelativePointerInBadContext => { - "Found a function relative pointer in a context that does not have a function base." - } - Error::CannotParseOmitPointerEncoding => { - "Cannot parse a pointer with a `DW_EH_PE_omit` encoding." - } - Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value", - Error::BadSignedLeb128 => "An error parsing a signed LEB128 value", - Error::AbbreviationTagZero => { - "An abbreviation declared that its tag is zero, - but zero is reserved for null records" - } - Error::AttributeFormZero => { - "An attribute specification declared that its form is zero, - but zero is reserved for null records" - } - Error::BadHasChildren => { - "The abbreviation's has-children byte was not one of - `DW_CHILDREN_{yes,no}`" - } - Error::BadLength => "The specified length is impossible", - Error::UnknownForm => "Found an unknown `DW_FORM_*` type", - Error::ExpectedZero => "Expected a zero, found something else", - Error::DuplicateAbbreviationCode => { - "Found an abbreviation code that has already been used" - } - Error::DuplicateArange => "Found a duplicate arange", - Error::UnknownReservedLength => "Found an unknown reserved length value", - Error::UnknownVersion(_) => "Found an unknown DWARF version", - Error::UnknownAbbreviation => "Found a record with an unknown abbreviation code", - Error::UnexpectedEof(_) => "Hit the end of input before it was expected", - Error::UnexpectedNull => "Read a null entry before it was expected.", - Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode", - Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode", - Error::UnsupportedAddressSize(_) => "The specified address size is not supported", - Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported", - Error::UnsupportedFieldSize(_) => "The specified field size is not supported", - Error::MinimumInstructionLengthZero => { - "The minimum instruction length must not be zero." - } - Error::MaximumOperationsPerInstructionZero => { - "The maximum operations per instruction must not be zero." - } - Error::LineRangeZero => "The line range must not be zero.", - Error::OpcodeBaseZero => "The opcode base must not be zero.", - Error::BadUtf8 => "Found an invalid UTF-8 string.", - Error::NotCieId => "Expected to find the CIE ID, but found something else.", - Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.", - Error::NotFdePointer => { - "Expected to find an FDE pointer, but found a CIE pointer instead." - } - Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression", - Error::InvalidPushObjectAddress => { - "DW_OP_push_object_address used but no object address given" - } - Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression", - Error::TooManyIterations => "Too many iterations to evaluate DWARF expression", - Error::InvalidExpression(_) => "Invalid opcode in DWARF expression", - Error::UnsupportedEvaluation => "Unsupported operation when evaluating expression", - Error::InvalidPiece => { - "DWARF expression has piece followed by non-piece expression at end" - } - Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece", - Error::DivisionByZero => "Division or modulus by zero when evaluating expression", - Error::TypeMismatch => "Type mismatch when evaluating expression", - Error::IntegralTypeRequired => "Integral type expected when evaluating expression", - Error::UnsupportedTypeOperation => { - "An expression operation used types that are not supported" - } - Error::InvalidShiftExpression => { - "The shift value in an expression must be a non-negative integer." - } - Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion", - Error::InvalidAddressRange => { - "The end of an address range must not be before the beginning." - } - Error::InvalidLocationAddressRange => { - "The end offset of a location list entry must not be before the beginning." - } - Error::CfiInstructionInInvalidContext => { - "Encountered a call frame instruction in a context in which it is not valid." - } - Error::PopWithEmptyStack => { - "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \ - instruction, but the stack was empty, and had nothing to pop." - } - Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.", - Error::UnsupportedOffset => { - "An offset value was larger than the maximum supported value." - } - Error::UnknownPointerEncoding => { - "The given pointer encoding is either unknown or invalid." - } - Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.", - Error::OffsetOutOfBounds => "The given offset is out of bounds.", - Error::UnknownAugmentation => "Found an unknown CFI augmentation.", - Error::UnsupportedPointerEncoding => { - "We do not support the given pointer encoding yet." - } - Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.", - Error::TooManyRegisterRules => { - "The CFI program defined more register rules than we have storage for." - } - Error::StackFull => { - "Attempted to push onto the CFI stack, but it was already at full capacity." - } - Error::VariableLengthSearchTable => { - "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \ - which makes binary search impossible." - } - Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet", - Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet", - Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet", - Error::MissingUnitDie => { - "A compilation unit or type unit is missing its top level DIE." - } - Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.", - Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.", - Error::ExpectedStringAttributeValue => { - "Expected an attribute value to be a string form." - } - Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.", - Error::InvalidIndexSectionCount => "Invalid section count in `.dwp` index.", - Error::InvalidIndexSlotCount => "Invalid slot count in `.dwp` index.", - Error::InvalidIndexRow => "Invalid hash row in `.dwp` index.", - Error::UnknownIndexSection => "Unknown section type in `.dwp` index.", - } - } -} - -#[cfg(feature = "std")] -impl error::Error for Error {} - -#[cfg(feature = "std")] -impl From<io::Error> for Error { - fn from(_: io::Error) -> Self { - Error::Io - } -} - -/// The result of a parse. -pub type Result<T> = result::Result<T, Error>; - -/// A convenience trait for loading DWARF sections from object files. To be -/// used like: -/// -/// ``` -/// use gimli::{DebugInfo, EndianSlice, LittleEndian, Reader, Section}; -/// -/// let buf = [0x00, 0x01, 0x02, 0x03]; -/// let reader = EndianSlice::new(&buf, LittleEndian); -/// let loader = |name| -> Result<_, ()> { Ok(reader) }; -/// -/// let debug_info: DebugInfo<_> = Section::load(loader).unwrap(); -/// ``` -pub trait Section<R>: From<R> { - /// Returns the section id for this type. - fn id() -> SectionId; - - /// Returns the ELF section name for this type. - fn section_name() -> &'static str { - Self::id().name() - } - - /// Returns the ELF section name (if any) for this type when used in a dwo - /// file. - fn dwo_section_name() -> Option<&'static str> { - Self::id().dwo_name() - } - - /// Returns the XCOFF section name (if any) for this type when used in a XCOFF - /// file. - fn xcoff_section_name() -> Option<&'static str> { - Self::id().xcoff_name() - } - - /// Try to load the section using the given loader function. - fn load<F, E>(f: F) -> core::result::Result<Self, E> - where - F: FnOnce(SectionId) -> core::result::Result<R, E>, - { - f(Self::id()).map(From::from) - } - - /// Returns the `Reader` for this section. - fn reader(&self) -> &R - where - R: Reader; - - /// Returns the subrange of the section that is the contribution of - /// a unit in a `.dwp` file. - fn dwp_range(&self, offset: u32, size: u32) -> Result<Self> - where - R: Reader, - { - let mut data = self.reader().clone(); - data.skip(R::Offset::from_u32(offset))?; - data.truncate(R::Offset::from_u32(size))?; - Ok(data.into()) - } - - /// Returns the `Reader` for this section. - fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> - where - R: Reader, - { - self.reader() - .lookup_offset_id(id) - .map(|offset| (Self::id(), offset)) - } -} - -impl Register { - pub(crate) fn from_u64(x: u64) -> Result<Register> { - let y = x as u16; - if u64::from(y) == x { - Ok(Register(y)) - } else { - Err(Error::UnsupportedRegister(x)) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::common::Format; - use crate::endianity::LittleEndian; - use test_assembler::{Endian, Section}; - - #[test] - fn test_parse_initial_length_32_ok() { - let section = Section::with_endian(Endian::Little).L32(0x7856_3412); - let buf = section.get_contents().unwrap(); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - match input.read_initial_length() { - Ok((length, format)) => { - assert_eq!(input.len(), 0); - assert_eq!(format, Format::Dwarf32); - assert_eq!(0x7856_3412, length); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - fn test_parse_initial_length_64_ok() { - let section = Section::with_endian(Endian::Little) - // Dwarf_64_INITIAL_UNIT_LENGTH - .L32(0xffff_ffff) - // Actual length - .L64(0xffde_bc9a_7856_3412); - let buf = section.get_contents().unwrap(); - let input = &mut EndianSlice::new(&buf, LittleEndian); - - #[cfg(target_pointer_width = "64")] - match input.read_initial_length() { - Ok((length, format)) => { - assert_eq!(input.len(), 0); - assert_eq!(format, Format::Dwarf64); - assert_eq!(0xffde_bc9a_7856_3412, length); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - - #[cfg(target_pointer_width = "32")] - match input.read_initial_length() { - Err(Error::UnsupportedOffset) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_initial_length_unknown_reserved_value() { - let section = Section::with_endian(Endian::Little).L32(0xffff_fffe); - let buf = section.get_contents().unwrap(); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - match input.read_initial_length() { - Err(Error::UnknownReservedLength) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_initial_length_incomplete() { - let buf = [0xff, 0xff, 0xff]; // Need at least 4 bytes. - - let input = &mut EndianSlice::new(&buf, LittleEndian); - match input.read_initial_length() { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_initial_length_64_incomplete() { - let section = Section::with_endian(Endian::Little) - // Dwarf_64_INITIAL_UNIT_LENGTH - .L32(0xffff_ffff) - // Actual length is not long enough. - .L32(0x7856_3412); - let buf = section.get_contents().unwrap(); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - match input.read_initial_length() { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_offset_32() { - let section = Section::with_endian(Endian::Little).L32(0x0123_4567); - let buf = section.get_contents().unwrap(); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - match input.read_offset(Format::Dwarf32) { - Ok(val) => { - assert_eq!(input.len(), 0); - assert_eq!(val, 0x0123_4567); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_offset_64_small() { - let section = Section::with_endian(Endian::Little).L64(0x0123_4567); - let buf = section.get_contents().unwrap(); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - match input.read_offset(Format::Dwarf64) { - Ok(val) => { - assert_eq!(input.len(), 0); - assert_eq!(val, 0x0123_4567); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_offset_64_large() { - let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); - let buf = section.get_contents().unwrap(); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - match input.read_offset(Format::Dwarf64) { - Ok(val) => { - assert_eq!(input.len(), 0); - assert_eq!(val, 0x0123_4567_89ab_cdef); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - #[cfg(target_pointer_width = "32")] - fn test_parse_offset_64_large() { - let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); - let buf = section.get_contents().unwrap(); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - match input.read_offset(Format::Dwarf64) { - Err(Error::UnsupportedOffset) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } -} diff --git a/vendor/gimli/src/read/op.rs b/vendor/gimli/src/read/op.rs deleted file mode 100644 index 4cb681e..0000000 --- a/vendor/gimli/src/read/op.rs +++ /dev/null @@ -1,4140 +0,0 @@ -//! Functions for parsing and evaluating DWARF expressions. - -#[cfg(feature = "read")] -use alloc::vec::Vec; -use core::mem; - -use super::util::{ArrayLike, ArrayVec}; -use crate::common::{DebugAddrIndex, DebugInfoOffset, Encoding, Register}; -use crate::constants; -use crate::read::{Error, Reader, ReaderOffset, Result, StoreOnHeap, UnitOffset, Value, ValueType}; - -/// A reference to a DIE, either relative to the current CU or -/// relative to the section. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DieReference<T = usize> { - /// A CU-relative reference. - UnitRef(UnitOffset<T>), - /// A section-relative reference. - DebugInfoRef(DebugInfoOffset<T>), -} - -/// A single decoded DWARF expression operation. -/// -/// DWARF expression evaluation is done in two parts: first the raw -/// bytes of the next part of the expression are decoded; and then the -/// decoded operation is evaluated. This approach lets other -/// consumers inspect the DWARF expression without reimplementing the -/// decoding operation. -/// -/// Multiple DWARF opcodes may decode into a single `Operation`. For -/// example, both `DW_OP_deref` and `DW_OP_xderef` are represented -/// using `Operation::Deref`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Operation<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Dereference the topmost value of the stack. - Deref { - /// The DIE of the base type or 0 to indicate the generic type - base_type: UnitOffset<Offset>, - /// The size of the data to dereference. - size: u8, - /// True if the dereference operation takes an address space - /// argument from the stack; false otherwise. - space: bool, - }, - /// Drop an item from the stack. - Drop, - /// Pick an item from the stack and push it on top of the stack. - /// This operation handles `DW_OP_pick`, `DW_OP_dup`, and - /// `DW_OP_over`. - Pick { - /// The index, from the top of the stack, of the item to copy. - index: u8, - }, - /// Swap the top two stack items. - Swap, - /// Rotate the top three stack items. - Rot, - /// Take the absolute value of the top of the stack. - Abs, - /// Bitwise `and` of the top two values on the stack. - And, - /// Divide the top two values on the stack. - Div, - /// Subtract the top two values on the stack. - Minus, - /// Modulus of the top two values on the stack. - Mod, - /// Multiply the top two values on the stack. - Mul, - /// Negate the top of the stack. - Neg, - /// Bitwise `not` of the top of the stack. - Not, - /// Bitwise `or` of the top two values on the stack. - Or, - /// Add the top two values on the stack. - Plus, - /// Add a constant to the topmost value on the stack. - PlusConstant { - /// The value to add. - value: u64, - }, - /// Logical left shift of the 2nd value on the stack by the number - /// of bits given by the topmost value on the stack. - Shl, - /// Right shift of the 2nd value on the stack by the number of - /// bits given by the topmost value on the stack. - Shr, - /// Arithmetic left shift of the 2nd value on the stack by the - /// number of bits given by the topmost value on the stack. - Shra, - /// Bitwise `xor` of the top two values on the stack. - Xor, - /// Branch to the target location if the top of stack is nonzero. - Bra { - /// The relative offset to the target bytecode. - target: i16, - }, - /// Compare the top two stack values for equality. - Eq, - /// Compare the top two stack values using `>=`. - Ge, - /// Compare the top two stack values using `>`. - Gt, - /// Compare the top two stack values using `<=`. - Le, - /// Compare the top two stack values using `<`. - Lt, - /// Compare the top two stack values using `!=`. - Ne, - /// Unconditional branch to the target location. - Skip { - /// The relative offset to the target bytecode. - target: i16, - }, - /// Push an unsigned constant value on the stack. This handles multiple - /// DWARF opcodes. - UnsignedConstant { - /// The value to push. - value: u64, - }, - /// Push a signed constant value on the stack. This handles multiple - /// DWARF opcodes. - SignedConstant { - /// The value to push. - value: i64, - }, - /// Indicate that this piece's location is in the given register. - /// - /// Completes the piece or expression. - Register { - /// The register number. - register: Register, - }, - /// Find the value of the given register, add the offset, and then - /// push the resulting sum on the stack. - RegisterOffset { - /// The register number. - register: Register, - /// The offset to add. - offset: i64, - /// The DIE of the base type or 0 to indicate the generic type - base_type: UnitOffset<Offset>, - }, - /// Compute the frame base (using `DW_AT_frame_base`), add the - /// given offset, and then push the resulting sum on the stack. - FrameOffset { - /// The offset to add. - offset: i64, - }, - /// No operation. - Nop, - /// Push the object address on the stack. - PushObjectAddress, - /// Evaluate a DWARF expression as a subroutine. The expression - /// comes from the `DW_AT_location` attribute of the indicated - /// DIE. - Call { - /// The DIE to use. - offset: DieReference<Offset>, - }, - /// Compute the address of a thread-local variable and push it on - /// the stack. - TLS, - /// Compute the call frame CFA and push it on the stack. - CallFrameCFA, - /// Terminate a piece. - Piece { - /// The size of this piece in bits. - size_in_bits: u64, - /// The bit offset of this piece. If `None`, then this piece - /// was specified using `DW_OP_piece` and should start at the - /// next byte boundary. - bit_offset: Option<u64>, - }, - /// The object has no location, but has a known constant value. - /// - /// Represents `DW_OP_implicit_value`. - /// Completes the piece or expression. - ImplicitValue { - /// The implicit value to use. - data: R, - }, - /// The object has no location, but its value is at the top of the stack. - /// - /// Represents `DW_OP_stack_value`. - /// Completes the piece or expression. - StackValue, - /// The object is a pointer to a value which has no actual location, - /// such as an implicit value or a stack value. - /// - /// Represents `DW_OP_implicit_pointer`. - /// Completes the piece or expression. - ImplicitPointer { - /// The `.debug_info` offset of the value that this is an implicit pointer into. - value: DebugInfoOffset<Offset>, - /// The byte offset into the value that the implicit pointer points to. - byte_offset: i64, - }, - /// Evaluate an expression at the entry to the current subprogram, and push it on the stack. - /// - /// Represents `DW_OP_entry_value`. - EntryValue { - /// The expression to be evaluated. - expression: R, - }, - /// This represents a parameter that was optimized out. - /// - /// The offset points to the definition of the parameter, and is - /// matched to the `DW_TAG_GNU_call_site_parameter` in the caller that also - /// points to the same definition of the parameter. - /// - /// Represents `DW_OP_GNU_parameter_ref`. - ParameterRef { - /// The DIE to use. - offset: UnitOffset<Offset>, - }, - /// Relocate the address if needed, and push it on the stack. - /// - /// Represents `DW_OP_addr`. - Address { - /// The offset to add. - address: u64, - }, - /// Read the address at the given index in `.debug_addr, relocate the address if needed, - /// and push it on the stack. - /// - /// Represents `DW_OP_addrx`. - AddressIndex { - /// The index of the address in `.debug_addr`. - index: DebugAddrIndex<Offset>, - }, - /// Read the address at the given index in `.debug_addr, and push it on the stack. - /// Do not relocate the address. - /// - /// Represents `DW_OP_constx`. - ConstantIndex { - /// The index of the address in `.debug_addr`. - index: DebugAddrIndex<Offset>, - }, - /// Interpret the value bytes as a constant of a given type, and push it on the stack. - /// - /// Represents `DW_OP_const_type`. - TypedLiteral { - /// The DIE of the base type. - base_type: UnitOffset<Offset>, - /// The value bytes. - value: R, - }, - /// Pop the top stack entry, convert it to a different type, and push it on the stack. - /// - /// Represents `DW_OP_convert`. - Convert { - /// The DIE of the base type. - base_type: UnitOffset<Offset>, - }, - /// Pop the top stack entry, reinterpret the bits in its value as a different type, - /// and push it on the stack. - /// - /// Represents `DW_OP_reinterpret`. - Reinterpret { - /// The DIE of the base type. - base_type: UnitOffset<Offset>, - }, - /// The index of a local in the currently executing function. - /// - /// Represents `DW_OP_WASM_location 0x00`. - /// Completes the piece or expression. - WasmLocal { - /// The index of the local. - index: u32, - }, - /// The index of a global. - /// - /// Represents `DW_OP_WASM_location 0x01` or `DW_OP_WASM_location 0x03`. - /// Completes the piece or expression. - WasmGlobal { - /// The index of the global. - index: u32, - }, - /// The index of an item on the operand stack. - /// - /// Represents `DW_OP_WASM_location 0x02`. - /// Completes the piece or expression. - WasmStack { - /// The index of the stack item. 0 is the bottom of the operand stack. - index: u32, - }, -} - -#[derive(Debug)] -enum OperationEvaluationResult<R: Reader> { - Piece, - Incomplete, - Complete { location: Location<R> }, - Waiting(EvaluationWaiting<R>, EvaluationResult<R>), -} - -/// A single location of a piece of the result of a DWARF expression. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Location<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// The piece is empty. Ordinarily this means the piece has been - /// optimized away. - Empty, - /// The piece is found in a register. - Register { - /// The register number. - register: Register, - }, - /// The piece is found in memory. - Address { - /// The address. - address: u64, - }, - /// The piece has no location but its value is known. - Value { - /// The value. - value: Value, - }, - /// The piece is represented by some constant bytes. - Bytes { - /// The value. - value: R, - }, - /// The piece is a pointer to a value which has no actual location. - ImplicitPointer { - /// The `.debug_info` offset of the value that this is an implicit pointer into. - value: DebugInfoOffset<Offset>, - /// The byte offset into the value that the implicit pointer points to. - byte_offset: i64, - }, -} - -impl<R, Offset> Location<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Return true if the piece is empty. - pub fn is_empty(&self) -> bool { - matches!(*self, Location::Empty) - } -} - -/// The description of a single piece of the result of a DWARF -/// expression. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Piece<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// If given, the size of the piece in bits. If `None`, there - /// must be only one piece whose size is all of the object. - pub size_in_bits: Option<u64>, - /// If given, the bit offset of the piece within the location. - /// If the location is a `Location::Register` or `Location::Value`, - /// then this offset is from the least significant bit end of - /// the register or value. - /// If the location is a `Location::Address` then the offset uses - /// the bit numbering and direction conventions of the language - /// and target system. - /// - /// If `None`, the piece starts at the location. If the - /// location is a register whose size is larger than the piece, - /// then placement within the register is defined by the ABI. - pub bit_offset: Option<u64>, - /// Where this piece is to be found. - pub location: Location<R, Offset>, -} - -// A helper function to handle branch offsets. -fn compute_pc<R: Reader>(pc: &R, bytecode: &R, offset: i16) -> Result<R> { - let pc_offset = pc.offset_from(bytecode); - let new_pc_offset = pc_offset.wrapping_add(R::Offset::from_i16(offset)); - if new_pc_offset > bytecode.len() { - Err(Error::BadBranchTarget(new_pc_offset.into_u64())) - } else { - let mut new_pc = bytecode.clone(); - new_pc.skip(new_pc_offset)?; - Ok(new_pc) - } -} - -fn generic_type<O: ReaderOffset>() -> UnitOffset<O> { - UnitOffset(O::from_u64(0).unwrap()) -} - -impl<R, Offset> Operation<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Parse a single DWARF expression operation. - /// - /// This is useful when examining a DWARF expression for reasons other - /// than direct evaluation. - /// - /// `bytes` points to a the operation to decode. It should point into - /// the same array as `bytecode`, which should be the entire - /// expression. - pub fn parse(bytes: &mut R, encoding: Encoding) -> Result<Operation<R, Offset>> { - let opcode = bytes.read_u8()?; - let name = constants::DwOp(opcode); - match name { - constants::DW_OP_addr => { - let address = bytes.read_address(encoding.address_size)?; - Ok(Operation::Address { address }) - } - constants::DW_OP_deref => Ok(Operation::Deref { - base_type: generic_type(), - size: encoding.address_size, - space: false, - }), - constants::DW_OP_const1u => { - let value = bytes.read_u8()?; - Ok(Operation::UnsignedConstant { - value: u64::from(value), - }) - } - constants::DW_OP_const1s => { - let value = bytes.read_i8()?; - Ok(Operation::SignedConstant { - value: i64::from(value), - }) - } - constants::DW_OP_const2u => { - let value = bytes.read_u16()?; - Ok(Operation::UnsignedConstant { - value: u64::from(value), - }) - } - constants::DW_OP_const2s => { - let value = bytes.read_i16()?; - Ok(Operation::SignedConstant { - value: i64::from(value), - }) - } - constants::DW_OP_const4u => { - let value = bytes.read_u32()?; - Ok(Operation::UnsignedConstant { - value: u64::from(value), - }) - } - constants::DW_OP_const4s => { - let value = bytes.read_i32()?; - Ok(Operation::SignedConstant { - value: i64::from(value), - }) - } - constants::DW_OP_const8u => { - let value = bytes.read_u64()?; - Ok(Operation::UnsignedConstant { value }) - } - constants::DW_OP_const8s => { - let value = bytes.read_i64()?; - Ok(Operation::SignedConstant { value }) - } - constants::DW_OP_constu => { - let value = bytes.read_uleb128()?; - Ok(Operation::UnsignedConstant { value }) - } - constants::DW_OP_consts => { - let value = bytes.read_sleb128()?; - Ok(Operation::SignedConstant { value }) - } - constants::DW_OP_dup => Ok(Operation::Pick { index: 0 }), - constants::DW_OP_drop => Ok(Operation::Drop), - constants::DW_OP_over => Ok(Operation::Pick { index: 1 }), - constants::DW_OP_pick => { - let value = bytes.read_u8()?; - Ok(Operation::Pick { index: value }) - } - constants::DW_OP_swap => Ok(Operation::Swap), - constants::DW_OP_rot => Ok(Operation::Rot), - constants::DW_OP_xderef => Ok(Operation::Deref { - base_type: generic_type(), - size: encoding.address_size, - space: true, - }), - constants::DW_OP_abs => Ok(Operation::Abs), - constants::DW_OP_and => Ok(Operation::And), - constants::DW_OP_div => Ok(Operation::Div), - constants::DW_OP_minus => Ok(Operation::Minus), - constants::DW_OP_mod => Ok(Operation::Mod), - constants::DW_OP_mul => Ok(Operation::Mul), - constants::DW_OP_neg => Ok(Operation::Neg), - constants::DW_OP_not => Ok(Operation::Not), - constants::DW_OP_or => Ok(Operation::Or), - constants::DW_OP_plus => Ok(Operation::Plus), - constants::DW_OP_plus_uconst => { - let value = bytes.read_uleb128()?; - Ok(Operation::PlusConstant { value }) - } - constants::DW_OP_shl => Ok(Operation::Shl), - constants::DW_OP_shr => Ok(Operation::Shr), - constants::DW_OP_shra => Ok(Operation::Shra), - constants::DW_OP_xor => Ok(Operation::Xor), - constants::DW_OP_bra => { - let target = bytes.read_i16()?; - Ok(Operation::Bra { target }) - } - constants::DW_OP_eq => Ok(Operation::Eq), - constants::DW_OP_ge => Ok(Operation::Ge), - constants::DW_OP_gt => Ok(Operation::Gt), - constants::DW_OP_le => Ok(Operation::Le), - constants::DW_OP_lt => Ok(Operation::Lt), - constants::DW_OP_ne => Ok(Operation::Ne), - constants::DW_OP_skip => { - let target = bytes.read_i16()?; - Ok(Operation::Skip { target }) - } - constants::DW_OP_lit0 - | constants::DW_OP_lit1 - | constants::DW_OP_lit2 - | constants::DW_OP_lit3 - | constants::DW_OP_lit4 - | constants::DW_OP_lit5 - | constants::DW_OP_lit6 - | constants::DW_OP_lit7 - | constants::DW_OP_lit8 - | constants::DW_OP_lit9 - | constants::DW_OP_lit10 - | constants::DW_OP_lit11 - | constants::DW_OP_lit12 - | constants::DW_OP_lit13 - | constants::DW_OP_lit14 - | constants::DW_OP_lit15 - | constants::DW_OP_lit16 - | constants::DW_OP_lit17 - | constants::DW_OP_lit18 - | constants::DW_OP_lit19 - | constants::DW_OP_lit20 - | constants::DW_OP_lit21 - | constants::DW_OP_lit22 - | constants::DW_OP_lit23 - | constants::DW_OP_lit24 - | constants::DW_OP_lit25 - | constants::DW_OP_lit26 - | constants::DW_OP_lit27 - | constants::DW_OP_lit28 - | constants::DW_OP_lit29 - | constants::DW_OP_lit30 - | constants::DW_OP_lit31 => Ok(Operation::UnsignedConstant { - value: (opcode - constants::DW_OP_lit0.0).into(), - }), - constants::DW_OP_reg0 - | constants::DW_OP_reg1 - | constants::DW_OP_reg2 - | constants::DW_OP_reg3 - | constants::DW_OP_reg4 - | constants::DW_OP_reg5 - | constants::DW_OP_reg6 - | constants::DW_OP_reg7 - | constants::DW_OP_reg8 - | constants::DW_OP_reg9 - | constants::DW_OP_reg10 - | constants::DW_OP_reg11 - | constants::DW_OP_reg12 - | constants::DW_OP_reg13 - | constants::DW_OP_reg14 - | constants::DW_OP_reg15 - | constants::DW_OP_reg16 - | constants::DW_OP_reg17 - | constants::DW_OP_reg18 - | constants::DW_OP_reg19 - | constants::DW_OP_reg20 - | constants::DW_OP_reg21 - | constants::DW_OP_reg22 - | constants::DW_OP_reg23 - | constants::DW_OP_reg24 - | constants::DW_OP_reg25 - | constants::DW_OP_reg26 - | constants::DW_OP_reg27 - | constants::DW_OP_reg28 - | constants::DW_OP_reg29 - | constants::DW_OP_reg30 - | constants::DW_OP_reg31 => Ok(Operation::Register { - register: Register((opcode - constants::DW_OP_reg0.0).into()), - }), - constants::DW_OP_breg0 - | constants::DW_OP_breg1 - | constants::DW_OP_breg2 - | constants::DW_OP_breg3 - | constants::DW_OP_breg4 - | constants::DW_OP_breg5 - | constants::DW_OP_breg6 - | constants::DW_OP_breg7 - | constants::DW_OP_breg8 - | constants::DW_OP_breg9 - | constants::DW_OP_breg10 - | constants::DW_OP_breg11 - | constants::DW_OP_breg12 - | constants::DW_OP_breg13 - | constants::DW_OP_breg14 - | constants::DW_OP_breg15 - | constants::DW_OP_breg16 - | constants::DW_OP_breg17 - | constants::DW_OP_breg18 - | constants::DW_OP_breg19 - | constants::DW_OP_breg20 - | constants::DW_OP_breg21 - | constants::DW_OP_breg22 - | constants::DW_OP_breg23 - | constants::DW_OP_breg24 - | constants::DW_OP_breg25 - | constants::DW_OP_breg26 - | constants::DW_OP_breg27 - | constants::DW_OP_breg28 - | constants::DW_OP_breg29 - | constants::DW_OP_breg30 - | constants::DW_OP_breg31 => { - let value = bytes.read_sleb128()?; - Ok(Operation::RegisterOffset { - register: Register((opcode - constants::DW_OP_breg0.0).into()), - offset: value, - base_type: generic_type(), - }) - } - constants::DW_OP_regx => { - let register = bytes.read_uleb128().and_then(Register::from_u64)?; - Ok(Operation::Register { register }) - } - constants::DW_OP_fbreg => { - let value = bytes.read_sleb128()?; - Ok(Operation::FrameOffset { offset: value }) - } - constants::DW_OP_bregx => { - let register = bytes.read_uleb128().and_then(Register::from_u64)?; - let offset = bytes.read_sleb128()?; - Ok(Operation::RegisterOffset { - register, - offset, - base_type: generic_type(), - }) - } - constants::DW_OP_piece => { - let size = bytes.read_uleb128()?; - Ok(Operation::Piece { - size_in_bits: 8 * size, - bit_offset: None, - }) - } - constants::DW_OP_deref_size => { - let size = bytes.read_u8()?; - Ok(Operation::Deref { - base_type: generic_type(), - size, - space: false, - }) - } - constants::DW_OP_xderef_size => { - let size = bytes.read_u8()?; - Ok(Operation::Deref { - base_type: generic_type(), - size, - space: true, - }) - } - constants::DW_OP_nop => Ok(Operation::Nop), - constants::DW_OP_push_object_address => Ok(Operation::PushObjectAddress), - constants::DW_OP_call2 => { - let value = bytes.read_u16().map(R::Offset::from_u16)?; - Ok(Operation::Call { - offset: DieReference::UnitRef(UnitOffset(value)), - }) - } - constants::DW_OP_call4 => { - let value = bytes.read_u32().map(R::Offset::from_u32)?; - Ok(Operation::Call { - offset: DieReference::UnitRef(UnitOffset(value)), - }) - } - constants::DW_OP_call_ref => { - let value = bytes.read_offset(encoding.format)?; - Ok(Operation::Call { - offset: DieReference::DebugInfoRef(DebugInfoOffset(value)), - }) - } - constants::DW_OP_form_tls_address | constants::DW_OP_GNU_push_tls_address => { - Ok(Operation::TLS) - } - constants::DW_OP_call_frame_cfa => Ok(Operation::CallFrameCFA), - constants::DW_OP_bit_piece => { - let size = bytes.read_uleb128()?; - let offset = bytes.read_uleb128()?; - Ok(Operation::Piece { - size_in_bits: size, - bit_offset: Some(offset), - }) - } - constants::DW_OP_implicit_value => { - let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - let data = bytes.split(len)?; - Ok(Operation::ImplicitValue { data }) - } - constants::DW_OP_stack_value => Ok(Operation::StackValue), - constants::DW_OP_implicit_pointer | constants::DW_OP_GNU_implicit_pointer => { - let value = if encoding.version == 2 { - bytes - .read_address(encoding.address_size) - .and_then(Offset::from_u64)? - } else { - bytes.read_offset(encoding.format)? - }; - let byte_offset = bytes.read_sleb128()?; - Ok(Operation::ImplicitPointer { - value: DebugInfoOffset(value), - byte_offset, - }) - } - constants::DW_OP_addrx | constants::DW_OP_GNU_addr_index => { - let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - Ok(Operation::AddressIndex { - index: DebugAddrIndex(index), - }) - } - constants::DW_OP_constx | constants::DW_OP_GNU_const_index => { - let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - Ok(Operation::ConstantIndex { - index: DebugAddrIndex(index), - }) - } - constants::DW_OP_entry_value | constants::DW_OP_GNU_entry_value => { - let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - let expression = bytes.split(len)?; - Ok(Operation::EntryValue { expression }) - } - constants::DW_OP_GNU_parameter_ref => { - let value = bytes.read_u32().map(R::Offset::from_u32)?; - Ok(Operation::ParameterRef { - offset: UnitOffset(value), - }) - } - constants::DW_OP_const_type | constants::DW_OP_GNU_const_type => { - let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - let len = bytes.read_u8()?; - let value = bytes.split(R::Offset::from_u8(len))?; - Ok(Operation::TypedLiteral { - base_type: UnitOffset(base_type), - value, - }) - } - constants::DW_OP_regval_type | constants::DW_OP_GNU_regval_type => { - let register = bytes.read_uleb128().and_then(Register::from_u64)?; - let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - Ok(Operation::RegisterOffset { - register, - offset: 0, - base_type: UnitOffset(base_type), - }) - } - constants::DW_OP_deref_type | constants::DW_OP_GNU_deref_type => { - let size = bytes.read_u8()?; - let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - Ok(Operation::Deref { - base_type: UnitOffset(base_type), - size, - space: false, - }) - } - constants::DW_OP_xderef_type => { - let size = bytes.read_u8()?; - let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - Ok(Operation::Deref { - base_type: UnitOffset(base_type), - size, - space: true, - }) - } - constants::DW_OP_convert | constants::DW_OP_GNU_convert => { - let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - Ok(Operation::Convert { - base_type: UnitOffset(base_type), - }) - } - constants::DW_OP_reinterpret | constants::DW_OP_GNU_reinterpret => { - let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; - Ok(Operation::Reinterpret { - base_type: UnitOffset(base_type), - }) - } - constants::DW_OP_WASM_location => match bytes.read_u8()? { - 0x0 => { - let index = bytes.read_uleb128_u32()?; - Ok(Operation::WasmLocal { index }) - } - 0x1 => { - let index = bytes.read_uleb128_u32()?; - Ok(Operation::WasmGlobal { index }) - } - 0x2 => { - let index = bytes.read_uleb128_u32()?; - Ok(Operation::WasmStack { index }) - } - 0x3 => { - let index = bytes.read_u32()?; - Ok(Operation::WasmGlobal { index }) - } - _ => Err(Error::InvalidExpression(name)), - }, - _ => Err(Error::InvalidExpression(name)), - } - } -} - -#[derive(Debug)] -enum EvaluationState<R: Reader> { - Start(Option<u64>), - Ready, - Error(Error), - Complete, - Waiting(EvaluationWaiting<R>), -} - -#[derive(Debug)] -enum EvaluationWaiting<R: Reader> { - Memory, - Register { offset: i64 }, - FrameBase { offset: i64 }, - Tls, - Cfa, - AtLocation, - EntryValue, - ParameterRef, - RelocatedAddress, - IndexedAddress, - TypedLiteral { value: R }, - Convert, - Reinterpret, -} - -/// The state of an `Evaluation` after evaluating a DWARF expression. -/// The evaluation is either `Complete`, or it requires more data -/// to continue, as described by the variant. -#[derive(Debug, PartialEq)] -pub enum EvaluationResult<R: Reader> { - /// The `Evaluation` is complete, and `Evaluation::result()` can be called. - Complete, - /// The `Evaluation` needs a value from memory to proceed further. Once the - /// caller determines what value to provide it should resume the `Evaluation` - /// by calling `Evaluation::resume_with_memory`. - RequiresMemory { - /// The address of the value required. - address: u64, - /// The size of the value required. This is guaranteed to be at most the - /// word size of the target architecture. - size: u8, - /// If not `None`, a target-specific address space value. - space: Option<u64>, - /// The DIE of the base type or 0 to indicate the generic type - base_type: UnitOffset<R::Offset>, - }, - /// The `Evaluation` needs a value from a register to proceed further. Once - /// the caller determines what value to provide it should resume the - /// `Evaluation` by calling `Evaluation::resume_with_register`. - RequiresRegister { - /// The register number. - register: Register, - /// The DIE of the base type or 0 to indicate the generic type - base_type: UnitOffset<R::Offset>, - }, - /// The `Evaluation` needs the frame base address to proceed further. Once - /// the caller determines what value to provide it should resume the - /// `Evaluation` by calling `Evaluation::resume_with_frame_base`. The frame - /// base address is the address produced by the location description in the - /// `DW_AT_frame_base` attribute of the current function. - RequiresFrameBase, - /// The `Evaluation` needs a value from TLS to proceed further. Once the - /// caller determines what value to provide it should resume the - /// `Evaluation` by calling `Evaluation::resume_with_tls`. - RequiresTls(u64), - /// The `Evaluation` needs the CFA to proceed further. Once the caller - /// determines what value to provide it should resume the `Evaluation` by - /// calling `Evaluation::resume_with_call_frame_cfa`. - RequiresCallFrameCfa, - /// The `Evaluation` needs the DWARF expression at the given location to - /// proceed further. Once the caller determines what value to provide it - /// should resume the `Evaluation` by calling - /// `Evaluation::resume_with_at_location`. - RequiresAtLocation(DieReference<R::Offset>), - /// The `Evaluation` needs the value produced by evaluating a DWARF - /// expression at the entry point of the current subprogram. Once the - /// caller determines what value to provide it should resume the - /// `Evaluation` by calling `Evaluation::resume_with_entry_value`. - RequiresEntryValue(Expression<R>), - /// The `Evaluation` needs the value of the parameter at the given location - /// in the current function's caller. Once the caller determines what value - /// to provide it should resume the `Evaluation` by calling - /// `Evaluation::resume_with_parameter_ref`. - RequiresParameterRef(UnitOffset<R::Offset>), - /// The `Evaluation` needs an address to be relocated to proceed further. - /// Once the caller determines what value to provide it should resume the - /// `Evaluation` by calling `Evaluation::resume_with_relocated_address`. - RequiresRelocatedAddress(u64), - /// The `Evaluation` needs an address from the `.debug_addr` section. - /// This address may also need to be relocated. - /// Once the caller determines what value to provide it should resume the - /// `Evaluation` by calling `Evaluation::resume_with_indexed_address`. - RequiresIndexedAddress { - /// The index of the address in the `.debug_addr` section, - /// relative to the `DW_AT_addr_base` of the compilation unit. - index: DebugAddrIndex<R::Offset>, - /// Whether the address also needs to be relocated. - relocate: bool, - }, - /// The `Evaluation` needs the `ValueType` for the base type DIE at - /// the give unit offset. Once the caller determines what value to provide it - /// should resume the `Evaluation` by calling - /// `Evaluation::resume_with_base_type`. - RequiresBaseType(UnitOffset<R::Offset>), -} - -/// The bytecode for a DWARF expression or location description. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Expression<R: Reader>(pub R); - -impl<R: Reader> Expression<R> { - /// Create an evaluation for this expression. - /// - /// The `encoding` is determined by the - /// [`CompilationUnitHeader`](struct.CompilationUnitHeader.html) or - /// [`TypeUnitHeader`](struct.TypeUnitHeader.html) that this expression - /// relates to. - /// - /// # Examples - /// ```rust,no_run - /// use gimli::Expression; - /// # let endian = gimli::LittleEndian; - /// # let debug_info = gimli::DebugInfo::from(gimli::EndianSlice::new(&[], endian)); - /// # let unit = debug_info.units().next().unwrap().unwrap(); - /// # let bytecode = gimli::EndianSlice::new(&[], endian); - /// let expression = gimli::Expression(bytecode); - /// let mut eval = expression.evaluation(unit.encoding()); - /// let mut result = eval.evaluate().unwrap(); - /// ``` - #[cfg(feature = "read")] - #[inline] - pub fn evaluation(self, encoding: Encoding) -> Evaluation<R> { - Evaluation::new(self.0, encoding) - } - - /// Return an iterator for the operations in the expression. - pub fn operations(self, encoding: Encoding) -> OperationIter<R> { - OperationIter { - input: self.0, - encoding, - } - } -} - -/// An iterator for the operations in an expression. -#[derive(Debug, Clone, Copy)] -pub struct OperationIter<R: Reader> { - input: R, - encoding: Encoding, -} - -impl<R: Reader> OperationIter<R> { - /// Read the next operation in an expression. - pub fn next(&mut self) -> Result<Option<Operation<R>>> { - if self.input.is_empty() { - return Ok(None); - } - match Operation::parse(&mut self.input, self.encoding) { - Ok(op) => Ok(Some(op)), - Err(e) => { - self.input.empty(); - Err(e) - } - } - } - - /// Return the current byte offset of the iterator. - pub fn offset_from(&self, expression: &Expression<R>) -> R::Offset { - self.input.offset_from(&expression.0) - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for OperationIter<R> { - type Item = Operation<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - OperationIter::next(self) - } -} - -/// Specification of what storage should be used for [`Evaluation`]. -/// -#[cfg_attr( - feature = "read", - doc = " -Normally you would only need to use [`StoreOnHeap`], which places the stacks and the results -on the heap using [`Vec`]. This is the default storage type parameter for [`Evaluation`]. -" -)] -/// -/// If you need to avoid [`Evaluation`] from allocating memory, e.g. for signal safety, -/// you can provide you own storage specification: -/// ```rust,no_run -/// # use gimli::*; -/// # let bytecode = EndianSlice::new(&[], LittleEndian); -/// # let encoding = unimplemented!(); -/// # let get_register_value = |_, _| Value::Generic(42); -/// # let get_frame_base = || 0xdeadbeef; -/// # -/// struct StoreOnStack; -/// -/// impl<R: Reader> EvaluationStorage<R> for StoreOnStack { -/// type Stack = [Value; 64]; -/// type ExpressionStack = [(R, R); 4]; -/// type Result = [Piece<R>; 1]; -/// } -/// -/// let mut eval = Evaluation::<_, StoreOnStack>::new_in(bytecode, encoding); -/// let mut result = eval.evaluate().unwrap(); -/// while result != EvaluationResult::Complete { -/// match result { -/// EvaluationResult::RequiresRegister { register, base_type } => { -/// let value = get_register_value(register, base_type); -/// result = eval.resume_with_register(value).unwrap(); -/// }, -/// EvaluationResult::RequiresFrameBase => { -/// let frame_base = get_frame_base(); -/// result = eval.resume_with_frame_base(frame_base).unwrap(); -/// }, -/// _ => unimplemented!(), -/// }; -/// } -/// -/// let result = eval.as_result(); -/// println!("{:?}", result); -/// ``` -pub trait EvaluationStorage<R: Reader> { - /// The storage used for the evaluation stack. - type Stack: ArrayLike<Item = Value>; - /// The storage used for the expression stack. - type ExpressionStack: ArrayLike<Item = (R, R)>; - /// The storage used for the results. - type Result: ArrayLike<Item = Piece<R>>; -} - -#[cfg(feature = "read")] -impl<R: Reader> EvaluationStorage<R> for StoreOnHeap { - type Stack = Vec<Value>; - type ExpressionStack = Vec<(R, R)>; - type Result = Vec<Piece<R>>; -} - -/// A DWARF expression evaluator. -/// -/// # Usage -/// A DWARF expression may require additional data to produce a final result, -/// such as the value of a register or a memory location. Once initial setup -/// is complete (i.e. `set_initial_value()`, `set_object_address()`) the -/// consumer calls the `evaluate()` method. That returns an `EvaluationResult`, -/// which is either `EvaluationResult::Complete` or a value indicating what -/// data is needed to resume the `Evaluation`. The consumer is responsible for -/// producing that data and resuming the computation with the correct method, -/// as documented for `EvaluationResult`. Only once an `EvaluationResult::Complete` -/// is returned can the consumer call `result()`. -/// -/// This design allows the consumer of `Evaluation` to decide how and when to -/// produce the required data and resume the computation. The `Evaluation` can -/// be driven synchronously (as shown below) or by some asynchronous mechanism -/// such as futures. -/// -/// # Examples -/// ```rust,no_run -/// use gimli::{Evaluation, EvaluationResult, Expression}; -/// # let bytecode = gimli::EndianSlice::new(&[], gimli::LittleEndian); -/// # let encoding = unimplemented!(); -/// # let get_register_value = |_, _| gimli::Value::Generic(42); -/// # let get_frame_base = || 0xdeadbeef; -/// -/// let mut eval = Evaluation::new(bytecode, encoding); -/// let mut result = eval.evaluate().unwrap(); -/// while result != EvaluationResult::Complete { -/// match result { -/// EvaluationResult::RequiresRegister { register, base_type } => { -/// let value = get_register_value(register, base_type); -/// result = eval.resume_with_register(value).unwrap(); -/// }, -/// EvaluationResult::RequiresFrameBase => { -/// let frame_base = get_frame_base(); -/// result = eval.resume_with_frame_base(frame_base).unwrap(); -/// }, -/// _ => unimplemented!(), -/// }; -/// } -/// -/// let result = eval.result(); -/// println!("{:?}", result); -/// ``` -#[derive(Debug)] -pub struct Evaluation<R: Reader, S: EvaluationStorage<R> = StoreOnHeap> { - bytecode: R, - encoding: Encoding, - object_address: Option<u64>, - max_iterations: Option<u32>, - iteration: u32, - state: EvaluationState<R>, - - // Stack operations are done on word-sized values. We do all - // operations on 64-bit values, and then mask the results - // appropriately when popping. - addr_mask: u64, - - // The stack. - stack: ArrayVec<S::Stack>, - - // The next operation to decode and evaluate. - pc: R, - - // If we see a DW_OP_call* operation, the previous PC and bytecode - // is stored here while evaluating the subroutine. - expression_stack: ArrayVec<S::ExpressionStack>, - - value_result: Option<Value>, - result: ArrayVec<S::Result>, -} - -#[cfg(feature = "read")] -impl<R: Reader> Evaluation<R> { - /// Create a new DWARF expression evaluator. - /// - /// The new evaluator is created without an initial value, without - /// an object address, and without a maximum number of iterations. - pub fn new(bytecode: R, encoding: Encoding) -> Self { - Self::new_in(bytecode, encoding) - } - - /// Get the result of this `Evaluation`. - /// - /// # Panics - /// Panics if this `Evaluation` has not been driven to completion. - pub fn result(self) -> Vec<Piece<R>> { - match self.state { - EvaluationState::Complete => self.result.into_vec(), - _ => { - panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed") - } - } - } -} - -impl<R: Reader, S: EvaluationStorage<R>> Evaluation<R, S> { - /// Create a new DWARF expression evaluator. - /// - /// The new evaluator is created without an initial value, without - /// an object address, and without a maximum number of iterations. - pub fn new_in(bytecode: R, encoding: Encoding) -> Self { - let pc = bytecode.clone(); - Evaluation { - bytecode, - encoding, - object_address: None, - max_iterations: None, - iteration: 0, - state: EvaluationState::Start(None), - addr_mask: if encoding.address_size == 8 { - !0u64 - } else { - (1 << (8 * u64::from(encoding.address_size))) - 1 - }, - stack: Default::default(), - expression_stack: Default::default(), - pc, - value_result: None, - result: Default::default(), - } - } - - /// Set an initial value to be pushed on the DWARF expression - /// evaluator's stack. This can be used in cases like - /// `DW_AT_vtable_elem_location`, which require a value on the - /// stack before evaluation commences. If no initial value is - /// set, and the expression uses an opcode requiring the initial - /// value, then evaluation will fail with an error. - /// - /// # Panics - /// Panics if `set_initial_value()` has already been called, or if - /// `evaluate()` has already been called. - pub fn set_initial_value(&mut self, value: u64) { - match self.state { - EvaluationState::Start(None) => { - self.state = EvaluationState::Start(Some(value)); - } - _ => panic!( - "`Evaluation::set_initial_value` was called twice, or after evaluation began." - ), - }; - } - - /// Set the enclosing object's address, as used by - /// `DW_OP_push_object_address`. If no object address is set, and - /// the expression uses an opcode requiring the object address, - /// then evaluation will fail with an error. - pub fn set_object_address(&mut self, value: u64) { - self.object_address = Some(value); - } - - /// Set the maximum number of iterations to be allowed by the - /// expression evaluator. - /// - /// An iteration corresponds approximately to the evaluation of a - /// single operation in an expression ("approximately" because the - /// implementation may allow two such operations in some cases). - /// The default is not to have a maximum; once set, it's not - /// possible to go back to this default state. This value can be - /// set to avoid denial of service attacks by bad DWARF bytecode. - pub fn set_max_iterations(&mut self, value: u32) { - self.max_iterations = Some(value); - } - - fn pop(&mut self) -> Result<Value> { - match self.stack.pop() { - Some(value) => Ok(value), - None => Err(Error::NotEnoughStackItems), - } - } - - fn push(&mut self, value: Value) -> Result<()> { - self.stack.try_push(value).map_err(|_| Error::StackFull) - } - - fn evaluate_one_operation(&mut self) -> Result<OperationEvaluationResult<R>> { - let operation = Operation::parse(&mut self.pc, self.encoding)?; - - match operation { - Operation::Deref { - base_type, - size, - space, - } => { - let entry = self.pop()?; - let addr = entry.to_u64(self.addr_mask)?; - let addr_space = if space { - let entry = self.pop()?; - let value = entry.to_u64(self.addr_mask)?; - Some(value) - } else { - None - }; - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::Memory, - EvaluationResult::RequiresMemory { - address: addr, - size, - space: addr_space, - base_type, - }, - )); - } - - Operation::Drop => { - self.pop()?; - } - Operation::Pick { index } => { - let len = self.stack.len(); - let index = index as usize; - if index >= len { - return Err(Error::NotEnoughStackItems); - } - let value = self.stack[len - index - 1]; - self.push(value)?; - } - Operation::Swap => { - let top = self.pop()?; - let next = self.pop()?; - self.push(top)?; - self.push(next)?; - } - Operation::Rot => { - let one = self.pop()?; - let two = self.pop()?; - let three = self.pop()?; - self.push(one)?; - self.push(three)?; - self.push(two)?; - } - - Operation::Abs => { - let value = self.pop()?; - let result = value.abs(self.addr_mask)?; - self.push(result)?; - } - Operation::And => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.and(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Div => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.div(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Minus => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.sub(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Mod => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.rem(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Mul => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.mul(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Neg => { - let v = self.pop()?; - let result = v.neg(self.addr_mask)?; - self.push(result)?; - } - Operation::Not => { - let value = self.pop()?; - let result = value.not(self.addr_mask)?; - self.push(result)?; - } - Operation::Or => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.or(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Plus => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.add(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::PlusConstant { value } => { - let lhs = self.pop()?; - let rhs = Value::from_u64(lhs.value_type(), value)?; - let result = lhs.add(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Shl => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.shl(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Shr => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.shr(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Shra => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.shra(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Xor => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.xor(rhs, self.addr_mask)?; - self.push(result)?; - } - - Operation::Bra { target } => { - let entry = self.pop()?; - let v = entry.to_u64(self.addr_mask)?; - if v != 0 { - self.pc = compute_pc(&self.pc, &self.bytecode, target)?; - } - } - - Operation::Eq => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.eq(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Ge => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.ge(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Gt => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.gt(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Le => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.le(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Lt => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.lt(rhs, self.addr_mask)?; - self.push(result)?; - } - Operation::Ne => { - let rhs = self.pop()?; - let lhs = self.pop()?; - let result = lhs.ne(rhs, self.addr_mask)?; - self.push(result)?; - } - - Operation::Skip { target } => { - self.pc = compute_pc(&self.pc, &self.bytecode, target)?; - } - - Operation::UnsignedConstant { value } => { - self.push(Value::Generic(value))?; - } - - Operation::SignedConstant { value } => { - self.push(Value::Generic(value as u64))?; - } - - Operation::RegisterOffset { - register, - offset, - base_type, - } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::Register { offset }, - EvaluationResult::RequiresRegister { - register, - base_type, - }, - )); - } - - Operation::FrameOffset { offset } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::FrameBase { offset }, - EvaluationResult::RequiresFrameBase, - )); - } - - Operation::Nop => {} - - Operation::PushObjectAddress => { - if let Some(value) = self.object_address { - self.push(Value::Generic(value))?; - } else { - return Err(Error::InvalidPushObjectAddress); - } - } - - Operation::Call { offset } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::AtLocation, - EvaluationResult::RequiresAtLocation(offset), - )); - } - - Operation::TLS => { - let entry = self.pop()?; - let index = entry.to_u64(self.addr_mask)?; - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::Tls, - EvaluationResult::RequiresTls(index), - )); - } - - Operation::CallFrameCFA => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::Cfa, - EvaluationResult::RequiresCallFrameCfa, - )); - } - - Operation::Register { register } => { - let location = Location::Register { register }; - return Ok(OperationEvaluationResult::Complete { location }); - } - - Operation::ImplicitValue { ref data } => { - let location = Location::Bytes { - value: data.clone(), - }; - return Ok(OperationEvaluationResult::Complete { location }); - } - - Operation::StackValue => { - let value = self.pop()?; - let location = Location::Value { value }; - return Ok(OperationEvaluationResult::Complete { location }); - } - - Operation::ImplicitPointer { value, byte_offset } => { - let location = Location::ImplicitPointer { value, byte_offset }; - return Ok(OperationEvaluationResult::Complete { location }); - } - - Operation::EntryValue { ref expression } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::EntryValue, - EvaluationResult::RequiresEntryValue(Expression(expression.clone())), - )); - } - - Operation::ParameterRef { offset } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::ParameterRef, - EvaluationResult::RequiresParameterRef(offset), - )); - } - - Operation::Address { address } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::RelocatedAddress, - EvaluationResult::RequiresRelocatedAddress(address), - )); - } - - Operation::AddressIndex { index } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::IndexedAddress, - EvaluationResult::RequiresIndexedAddress { - index, - relocate: true, - }, - )); - } - - Operation::ConstantIndex { index } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::IndexedAddress, - EvaluationResult::RequiresIndexedAddress { - index, - relocate: false, - }, - )); - } - - Operation::Piece { - size_in_bits, - bit_offset, - } => { - let location = if self.stack.is_empty() { - Location::Empty - } else { - let entry = self.pop()?; - let address = entry.to_u64(self.addr_mask)?; - Location::Address { address } - }; - self.result - .try_push(Piece { - size_in_bits: Some(size_in_bits), - bit_offset, - location, - }) - .map_err(|_| Error::StackFull)?; - return Ok(OperationEvaluationResult::Piece); - } - - Operation::TypedLiteral { base_type, value } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::TypedLiteral { value }, - EvaluationResult::RequiresBaseType(base_type), - )); - } - Operation::Convert { base_type } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::Convert, - EvaluationResult::RequiresBaseType(base_type), - )); - } - Operation::Reinterpret { base_type } => { - return Ok(OperationEvaluationResult::Waiting( - EvaluationWaiting::Reinterpret, - EvaluationResult::RequiresBaseType(base_type), - )); - } - Operation::WasmLocal { .. } - | Operation::WasmGlobal { .. } - | Operation::WasmStack { .. } => { - return Err(Error::UnsupportedEvaluation); - } - } - - Ok(OperationEvaluationResult::Incomplete) - } - - /// Get the result if this is an evaluation for a value. - /// - /// Returns `None` if the evaluation contained operations that are only - /// valid for location descriptions. - /// - /// # Panics - /// Panics if this `Evaluation` has not been driven to completion. - pub fn value_result(&self) -> Option<Value> { - match self.state { - EvaluationState::Complete => self.value_result, - _ => { - panic!("Called `Evaluation::value_result` on an `Evaluation` that has not been completed") - } - } - } - - /// Get the result of this `Evaluation`. - /// - /// # Panics - /// Panics if this `Evaluation` has not been driven to completion. - pub fn as_result(&self) -> &[Piece<R>] { - match self.state { - EvaluationState::Complete => &self.result, - _ => { - panic!( - "Called `Evaluation::as_result` on an `Evaluation` that has not been completed" - ) - } - } - } - - /// Evaluate a DWARF expression. This method should only ever be called - /// once. If the returned `EvaluationResult` is not - /// `EvaluationResult::Complete`, the caller should provide the required - /// value and resume the evaluation by calling the appropriate resume_with - /// method on `Evaluation`. - pub fn evaluate(&mut self) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Start(initial_value) => { - if let Some(value) = initial_value { - self.push(Value::Generic(value))?; - } - self.state = EvaluationState::Ready; - } - EvaluationState::Ready => {} - EvaluationState::Error(err) => return Err(err), - EvaluationState::Complete => return Ok(EvaluationResult::Complete), - EvaluationState::Waiting(_) => panic!(), - }; - - match self.evaluate_internal() { - Ok(r) => Ok(r), - Err(e) => { - self.state = EvaluationState::Error(e); - Err(e) - } - } - } - - /// Resume the `Evaluation` with the provided memory `value`. This will apply - /// the provided memory value to the evaluation and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresMemory`. - pub fn resume_with_memory(&mut self, value: Value) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::Memory) => { - self.push(value)?; - } - _ => panic!( - "Called `Evaluation::resume_with_memory` without a preceding `EvaluationResult::RequiresMemory`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided `register` value. This will apply - /// the provided register value to the evaluation and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresRegister`. - pub fn resume_with_register(&mut self, value: Value) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::Register { offset }) => { - let offset = Value::from_u64(value.value_type(), offset as u64)?; - let value = value.add(offset, self.addr_mask)?; - self.push(value)?; - } - _ => panic!( - "Called `Evaluation::resume_with_register` without a preceding `EvaluationResult::RequiresRegister`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided `frame_base`. This will - /// apply the provided frame base value to the evaluation and continue - /// evaluating opcodes until the evaluation is completed, reaches an error, - /// or needs more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresFrameBase`. - pub fn resume_with_frame_base(&mut self, frame_base: u64) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::FrameBase { offset }) => { - self.push(Value::Generic(frame_base.wrapping_add(offset as u64)))?; - } - _ => panic!( - "Called `Evaluation::resume_with_frame_base` without a preceding `EvaluationResult::RequiresFrameBase`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided `value`. This will apply - /// the provided TLS value to the evaluation and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresTls`. - pub fn resume_with_tls(&mut self, value: u64) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::Tls) => { - self.push(Value::Generic(value))?; - } - _ => panic!( - "Called `Evaluation::resume_with_tls` without a preceding `EvaluationResult::RequiresTls`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided `cfa`. This will - /// apply the provided CFA value to the evaluation and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresCallFrameCfa`. - pub fn resume_with_call_frame_cfa(&mut self, cfa: u64) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::Cfa) => { - self.push(Value::Generic(cfa))?; - } - _ => panic!( - "Called `Evaluation::resume_with_call_frame_cfa` without a preceding `EvaluationResult::RequiresCallFrameCfa`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided `bytes`. This will - /// continue processing the evaluation with the new expression provided - /// until the evaluation is completed, reaches an error, or needs more - /// information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresAtLocation`. - pub fn resume_with_at_location(&mut self, mut bytes: R) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::AtLocation) => { - if !bytes.is_empty() { - let mut pc = bytes.clone(); - mem::swap(&mut pc, &mut self.pc); - mem::swap(&mut bytes, &mut self.bytecode); - self.expression_stack.try_push((pc, bytes)).map_err(|_| Error::StackFull)?; - } - } - _ => panic!( - "Called `Evaluation::resume_with_at_location` without a precedeing `EvaluationResult::RequiresAtLocation`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided `entry_value`. This will - /// apply the provided entry value to the evaluation and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresEntryValue`. - pub fn resume_with_entry_value(&mut self, entry_value: Value) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::EntryValue) => { - self.push(entry_value)?; - } - _ => panic!( - "Called `Evaluation::resume_with_entry_value` without a preceding `EvaluationResult::RequiresEntryValue`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided `parameter_value`. This will - /// apply the provided parameter value to the evaluation and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresParameterRef`. - pub fn resume_with_parameter_ref( - &mut self, - parameter_value: u64, - ) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::ParameterRef) => { - self.push(Value::Generic(parameter_value))?; - } - _ => panic!( - "Called `Evaluation::resume_with_parameter_ref` without a preceding `EvaluationResult::RequiresParameterRef`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided relocated `address`. This will use the - /// provided relocated address for the operation that required it, and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with - /// `EvaluationResult::RequiresRelocatedAddress`. - pub fn resume_with_relocated_address(&mut self, address: u64) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::RelocatedAddress) => { - self.push(Value::Generic(address))?; - } - _ => panic!( - "Called `Evaluation::resume_with_relocated_address` without a preceding `EvaluationResult::RequiresRelocatedAddress`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided indexed `address`. This will use the - /// provided indexed address for the operation that required it, and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with - /// `EvaluationResult::RequiresIndexedAddress`. - pub fn resume_with_indexed_address(&mut self, address: u64) -> Result<EvaluationResult<R>> { - match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::IndexedAddress) => { - self.push(Value::Generic(address))?; - } - _ => panic!( - "Called `Evaluation::resume_with_indexed_address` without a preceding `EvaluationResult::RequiresIndexedAddress`" - ), - }; - - self.evaluate_internal() - } - - /// Resume the `Evaluation` with the provided `base_type`. This will use the - /// provided base type for the operation that required it, and continue evaluating - /// opcodes until the evaluation is completed, reaches an error, or needs - /// more information again. - /// - /// # Panics - /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresBaseType`. - pub fn resume_with_base_type(&mut self, base_type: ValueType) -> Result<EvaluationResult<R>> { - let value = match self.state { - EvaluationState::Error(err) => return Err(err), - EvaluationState::Waiting(EvaluationWaiting::TypedLiteral { ref value }) => { - Value::parse(base_type, value.clone())? - } - EvaluationState::Waiting(EvaluationWaiting::Convert) => { - let entry = self.pop()?; - entry.convert(base_type, self.addr_mask)? - } - EvaluationState::Waiting(EvaluationWaiting::Reinterpret) => { - let entry = self.pop()?; - entry.reinterpret(base_type, self.addr_mask)? - } - _ => panic!( - "Called `Evaluation::resume_with_base_type` without a preceding `EvaluationResult::RequiresBaseType`" - ), - }; - self.push(value)?; - self.evaluate_internal() - } - - fn end_of_expression(&mut self) -> bool { - while self.pc.is_empty() { - match self.expression_stack.pop() { - Some((newpc, newbytes)) => { - self.pc = newpc; - self.bytecode = newbytes; - } - None => return true, - } - } - false - } - - fn evaluate_internal(&mut self) -> Result<EvaluationResult<R>> { - while !self.end_of_expression() { - self.iteration += 1; - if let Some(max_iterations) = self.max_iterations { - if self.iteration > max_iterations { - return Err(Error::TooManyIterations); - } - } - - let op_result = self.evaluate_one_operation()?; - match op_result { - OperationEvaluationResult::Piece => {} - OperationEvaluationResult::Incomplete => { - if self.end_of_expression() && !self.result.is_empty() { - // We saw a piece earlier and then some - // unterminated piece. It's not clear this is - // well-defined. - return Err(Error::InvalidPiece); - } - } - OperationEvaluationResult::Complete { location } => { - if self.end_of_expression() { - if !self.result.is_empty() { - // We saw a piece earlier and then some - // unterminated piece. It's not clear this is - // well-defined. - return Err(Error::InvalidPiece); - } - self.result - .try_push(Piece { - size_in_bits: None, - bit_offset: None, - location, - }) - .map_err(|_| Error::StackFull)?; - } else { - // If there are more operations, then the next operation must - // be a Piece. - match Operation::parse(&mut self.pc, self.encoding)? { - Operation::Piece { - size_in_bits, - bit_offset, - } => { - self.result - .try_push(Piece { - size_in_bits: Some(size_in_bits), - bit_offset, - location, - }) - .map_err(|_| Error::StackFull)?; - } - _ => { - let value = - self.bytecode.len().into_u64() - self.pc.len().into_u64() - 1; - return Err(Error::InvalidExpressionTerminator(value)); - } - } - } - } - OperationEvaluationResult::Waiting(waiting, result) => { - self.state = EvaluationState::Waiting(waiting); - return Ok(result); - } - } - } - - // If no pieces have been seen, use the stack top as the - // result. - if self.result.is_empty() { - let entry = self.pop()?; - self.value_result = Some(entry); - let addr = entry.to_u64(self.addr_mask)?; - self.result - .try_push(Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Address { address: addr }, - }) - .map_err(|_| Error::StackFull)?; - } - - self.state = EvaluationState::Complete; - Ok(EvaluationResult::Complete) - } -} - -#[cfg(test)] -// Tests require leb128::write. -#[cfg(feature = "write")] -mod tests { - use super::*; - use crate::common::Format; - use crate::constants; - use crate::endianity::LittleEndian; - use crate::leb128; - use crate::read::{EndianSlice, Error, Result, UnitOffset}; - use crate::test_util::GimliSectionMethods; - use core::usize; - use test_assembler::{Endian, Section}; - - fn encoding4() -> Encoding { - Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - } - } - - fn encoding8() -> Encoding { - Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - } - } - - #[test] - fn test_compute_pc() { - // Contents don't matter for this test, just length. - let bytes = [0, 1, 2, 3, 4]; - let bytecode = &bytes[..]; - let ebuf = &EndianSlice::new(bytecode, LittleEndian); - - assert_eq!(compute_pc(ebuf, ebuf, 0), Ok(*ebuf)); - assert_eq!( - compute_pc(ebuf, ebuf, -1), - Err(Error::BadBranchTarget(usize::MAX as u64)) - ); - assert_eq!(compute_pc(ebuf, ebuf, 5), Ok(ebuf.range_from(5..))); - assert_eq!( - compute_pc(&ebuf.range_from(3..), ebuf, -2), - Ok(ebuf.range_from(1..)) - ); - assert_eq!( - compute_pc(&ebuf.range_from(2..), ebuf, 2), - Ok(ebuf.range_from(4..)) - ); - } - - fn check_op_parse_simple<'input>( - input: &'input [u8], - expect: &Operation<EndianSlice<'input, LittleEndian>>, - encoding: Encoding, - ) { - let buf = EndianSlice::new(input, LittleEndian); - let mut pc = buf; - let value = Operation::parse(&mut pc, encoding); - match value { - Ok(val) => { - assert_eq!(val, *expect); - assert_eq!(pc.len(), 0); - } - _ => panic!("Unexpected result"), - } - } - - fn check_op_parse_eof(input: &[u8], encoding: Encoding) { - let buf = EndianSlice::new(input, LittleEndian); - let mut pc = buf; - match Operation::parse(&mut pc, encoding) { - Err(Error::UnexpectedEof(id)) => { - assert!(buf.lookup_offset_id(id).is_some()); - } - - _ => panic!("Unexpected result"), - } - } - - fn check_op_parse<F>( - input: F, - expect: &Operation<EndianSlice<LittleEndian>>, - encoding: Encoding, - ) where - F: Fn(Section) -> Section, - { - let input = input(Section::with_endian(Endian::Little)) - .get_contents() - .unwrap(); - for i in 1..input.len() { - check_op_parse_eof(&input[..i], encoding); - } - check_op_parse_simple(&input, expect, encoding); - } - - #[test] - fn test_op_parse_onebyte() { - // Doesn't matter for this test. - let encoding = encoding4(); - - // Test all single-byte opcodes. - #[rustfmt::skip] - let inputs = [ - ( - constants::DW_OP_deref, - Operation::Deref { - base_type: generic_type(), - size: encoding.address_size, - space: false, - }, - ), - (constants::DW_OP_dup, Operation::Pick { index: 0 }), - (constants::DW_OP_drop, Operation::Drop), - (constants::DW_OP_over, Operation::Pick { index: 1 }), - (constants::DW_OP_swap, Operation::Swap), - (constants::DW_OP_rot, Operation::Rot), - ( - constants::DW_OP_xderef, - Operation::Deref { - base_type: generic_type(), - size: encoding.address_size, - space: true, - }, - ), - (constants::DW_OP_abs, Operation::Abs), - (constants::DW_OP_and, Operation::And), - (constants::DW_OP_div, Operation::Div), - (constants::DW_OP_minus, Operation::Minus), - (constants::DW_OP_mod, Operation::Mod), - (constants::DW_OP_mul, Operation::Mul), - (constants::DW_OP_neg, Operation::Neg), - (constants::DW_OP_not, Operation::Not), - (constants::DW_OP_or, Operation::Or), - (constants::DW_OP_plus, Operation::Plus), - (constants::DW_OP_shl, Operation::Shl), - (constants::DW_OP_shr, Operation::Shr), - (constants::DW_OP_shra, Operation::Shra), - (constants::DW_OP_xor, Operation::Xor), - (constants::DW_OP_eq, Operation::Eq), - (constants::DW_OP_ge, Operation::Ge), - (constants::DW_OP_gt, Operation::Gt), - (constants::DW_OP_le, Operation::Le), - (constants::DW_OP_lt, Operation::Lt), - (constants::DW_OP_ne, Operation::Ne), - (constants::DW_OP_lit0, Operation::UnsignedConstant { value: 0 }), - (constants::DW_OP_lit1, Operation::UnsignedConstant { value: 1 }), - (constants::DW_OP_lit2, Operation::UnsignedConstant { value: 2 }), - (constants::DW_OP_lit3, Operation::UnsignedConstant { value: 3 }), - (constants::DW_OP_lit4, Operation::UnsignedConstant { value: 4 }), - (constants::DW_OP_lit5, Operation::UnsignedConstant { value: 5 }), - (constants::DW_OP_lit6, Operation::UnsignedConstant { value: 6 }), - (constants::DW_OP_lit7, Operation::UnsignedConstant { value: 7 }), - (constants::DW_OP_lit8, Operation::UnsignedConstant { value: 8 }), - (constants::DW_OP_lit9, Operation::UnsignedConstant { value: 9 }), - (constants::DW_OP_lit10, Operation::UnsignedConstant { value: 10 }), - (constants::DW_OP_lit11, Operation::UnsignedConstant { value: 11 }), - (constants::DW_OP_lit12, Operation::UnsignedConstant { value: 12 }), - (constants::DW_OP_lit13, Operation::UnsignedConstant { value: 13 }), - (constants::DW_OP_lit14, Operation::UnsignedConstant { value: 14 }), - (constants::DW_OP_lit15, Operation::UnsignedConstant { value: 15 }), - (constants::DW_OP_lit16, Operation::UnsignedConstant { value: 16 }), - (constants::DW_OP_lit17, Operation::UnsignedConstant { value: 17 }), - (constants::DW_OP_lit18, Operation::UnsignedConstant { value: 18 }), - (constants::DW_OP_lit19, Operation::UnsignedConstant { value: 19 }), - (constants::DW_OP_lit20, Operation::UnsignedConstant { value: 20 }), - (constants::DW_OP_lit21, Operation::UnsignedConstant { value: 21 }), - (constants::DW_OP_lit22, Operation::UnsignedConstant { value: 22 }), - (constants::DW_OP_lit23, Operation::UnsignedConstant { value: 23 }), - (constants::DW_OP_lit24, Operation::UnsignedConstant { value: 24 }), - (constants::DW_OP_lit25, Operation::UnsignedConstant { value: 25 }), - (constants::DW_OP_lit26, Operation::UnsignedConstant { value: 26 }), - (constants::DW_OP_lit27, Operation::UnsignedConstant { value: 27 }), - (constants::DW_OP_lit28, Operation::UnsignedConstant { value: 28 }), - (constants::DW_OP_lit29, Operation::UnsignedConstant { value: 29 }), - (constants::DW_OP_lit30, Operation::UnsignedConstant { value: 30 }), - (constants::DW_OP_lit31, Operation::UnsignedConstant { value: 31 }), - (constants::DW_OP_reg0, Operation::Register { register: Register(0) }), - (constants::DW_OP_reg1, Operation::Register { register: Register(1) }), - (constants::DW_OP_reg2, Operation::Register { register: Register(2) }), - (constants::DW_OP_reg3, Operation::Register { register: Register(3) }), - (constants::DW_OP_reg4, Operation::Register { register: Register(4) }), - (constants::DW_OP_reg5, Operation::Register { register: Register(5) }), - (constants::DW_OP_reg6, Operation::Register { register: Register(6) }), - (constants::DW_OP_reg7, Operation::Register { register: Register(7) }), - (constants::DW_OP_reg8, Operation::Register { register: Register(8) }), - (constants::DW_OP_reg9, Operation::Register { register: Register(9) }), - (constants::DW_OP_reg10, Operation::Register { register: Register(10) }), - (constants::DW_OP_reg11, Operation::Register { register: Register(11) }), - (constants::DW_OP_reg12, Operation::Register { register: Register(12) }), - (constants::DW_OP_reg13, Operation::Register { register: Register(13) }), - (constants::DW_OP_reg14, Operation::Register { register: Register(14) }), - (constants::DW_OP_reg15, Operation::Register { register: Register(15) }), - (constants::DW_OP_reg16, Operation::Register { register: Register(16) }), - (constants::DW_OP_reg17, Operation::Register { register: Register(17) }), - (constants::DW_OP_reg18, Operation::Register { register: Register(18) }), - (constants::DW_OP_reg19, Operation::Register { register: Register(19) }), - (constants::DW_OP_reg20, Operation::Register { register: Register(20) }), - (constants::DW_OP_reg21, Operation::Register { register: Register(21) }), - (constants::DW_OP_reg22, Operation::Register { register: Register(22) }), - (constants::DW_OP_reg23, Operation::Register { register: Register(23) }), - (constants::DW_OP_reg24, Operation::Register { register: Register(24) }), - (constants::DW_OP_reg25, Operation::Register { register: Register(25) }), - (constants::DW_OP_reg26, Operation::Register { register: Register(26) }), - (constants::DW_OP_reg27, Operation::Register { register: Register(27) }), - (constants::DW_OP_reg28, Operation::Register { register: Register(28) }), - (constants::DW_OP_reg29, Operation::Register { register: Register(29) }), - (constants::DW_OP_reg30, Operation::Register { register: Register(30) }), - (constants::DW_OP_reg31, Operation::Register { register: Register(31) }), - (constants::DW_OP_nop, Operation::Nop), - (constants::DW_OP_push_object_address, Operation::PushObjectAddress), - (constants::DW_OP_form_tls_address, Operation::TLS), - (constants::DW_OP_GNU_push_tls_address, Operation::TLS), - (constants::DW_OP_call_frame_cfa, Operation::CallFrameCFA), - (constants::DW_OP_stack_value, Operation::StackValue), - ]; - - let input = []; - check_op_parse_eof(&input[..], encoding); - - for item in inputs.iter() { - let (opcode, ref result) = *item; - check_op_parse(|s| s.D8(opcode.0), result, encoding); - } - } - - #[test] - fn test_op_parse_twobyte() { - // Doesn't matter for this test. - let encoding = encoding4(); - - let inputs = [ - ( - constants::DW_OP_const1u, - 23, - Operation::UnsignedConstant { value: 23 }, - ), - ( - constants::DW_OP_const1s, - (-23i8) as u8, - Operation::SignedConstant { value: -23 }, - ), - (constants::DW_OP_pick, 7, Operation::Pick { index: 7 }), - ( - constants::DW_OP_deref_size, - 19, - Operation::Deref { - base_type: generic_type(), - size: 19, - space: false, - }, - ), - ( - constants::DW_OP_xderef_size, - 19, - Operation::Deref { - base_type: generic_type(), - size: 19, - space: true, - }, - ), - ]; - - for item in inputs.iter() { - let (opcode, arg, ref result) = *item; - check_op_parse(|s| s.D8(opcode.0).D8(arg), result, encoding); - } - } - - #[test] - fn test_op_parse_threebyte() { - // Doesn't matter for this test. - let encoding = encoding4(); - - // While bra and skip are 3-byte opcodes, they aren't tested here, - // but rather specially in their own function. - let inputs = [ - ( - constants::DW_OP_const2u, - 23, - Operation::UnsignedConstant { value: 23 }, - ), - ( - constants::DW_OP_const2s, - (-23i16) as u16, - Operation::SignedConstant { value: -23 }, - ), - ( - constants::DW_OP_call2, - 1138, - Operation::Call { - offset: DieReference::UnitRef(UnitOffset(1138)), - }, - ), - ( - constants::DW_OP_bra, - (-23i16) as u16, - Operation::Bra { target: -23 }, - ), - ( - constants::DW_OP_skip, - (-23i16) as u16, - Operation::Skip { target: -23 }, - ), - ]; - - for item in inputs.iter() { - let (opcode, arg, ref result) = *item; - check_op_parse(|s| s.D8(opcode.0).L16(arg), result, encoding); - } - } - - #[test] - fn test_op_parse_fivebyte() { - // There are some tests here that depend on address size. - let encoding = encoding4(); - - let inputs = [ - ( - constants::DW_OP_addr, - 0x1234_5678, - Operation::Address { - address: 0x1234_5678, - }, - ), - ( - constants::DW_OP_const4u, - 0x1234_5678, - Operation::UnsignedConstant { value: 0x1234_5678 }, - ), - ( - constants::DW_OP_const4s, - (-23i32) as u32, - Operation::SignedConstant { value: -23 }, - ), - ( - constants::DW_OP_call4, - 0x1234_5678, - Operation::Call { - offset: DieReference::UnitRef(UnitOffset(0x1234_5678)), - }, - ), - ( - constants::DW_OP_call_ref, - 0x1234_5678, - Operation::Call { - offset: DieReference::DebugInfoRef(DebugInfoOffset(0x1234_5678)), - }, - ), - ]; - - for item in inputs.iter() { - let (op, arg, ref expect) = *item; - check_op_parse(|s| s.D8(op.0).L32(arg), expect, encoding); - } - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_op_parse_ninebyte() { - // There are some tests here that depend on address size. - let encoding = encoding8(); - - let inputs = [ - ( - constants::DW_OP_addr, - 0x1234_5678_1234_5678, - Operation::Address { - address: 0x1234_5678_1234_5678, - }, - ), - ( - constants::DW_OP_const8u, - 0x1234_5678_1234_5678, - Operation::UnsignedConstant { - value: 0x1234_5678_1234_5678, - }, - ), - ( - constants::DW_OP_const8s, - (-23i64) as u64, - Operation::SignedConstant { value: -23 }, - ), - ( - constants::DW_OP_call_ref, - 0x1234_5678_1234_5678, - Operation::Call { - offset: DieReference::DebugInfoRef(DebugInfoOffset(0x1234_5678_1234_5678)), - }, - ), - ]; - - for item in inputs.iter() { - let (op, arg, ref expect) = *item; - check_op_parse(|s| s.D8(op.0).L64(arg), expect, encoding); - } - } - - #[test] - fn test_op_parse_sleb() { - // Doesn't matter for this test. - let encoding = encoding4(); - - let values = [ - -1i64, - 0, - 1, - 0x100, - 0x1eee_eeee, - 0x7fff_ffff_ffff_ffff, - -0x100, - -0x1eee_eeee, - -0x7fff_ffff_ffff_ffff, - ]; - for value in values.iter() { - let mut inputs = vec![ - ( - constants::DW_OP_consts.0, - Operation::SignedConstant { value: *value }, - ), - ( - constants::DW_OP_fbreg.0, - Operation::FrameOffset { offset: *value }, - ), - ]; - - for i in 0..32 { - inputs.push(( - constants::DW_OP_breg0.0 + i, - Operation::RegisterOffset { - register: Register(i.into()), - offset: *value, - base_type: UnitOffset(0), - }, - )); - } - - for item in inputs.iter() { - let (op, ref expect) = *item; - check_op_parse(|s| s.D8(op).sleb(*value), expect, encoding); - } - } - } - - #[test] - fn test_op_parse_uleb() { - // Doesn't matter for this test. - let encoding = encoding4(); - - let values = [ - 0, - 1, - 0x100, - (!0u16).into(), - 0x1eee_eeee, - 0x7fff_ffff_ffff_ffff, - !0u64, - ]; - for value in values.iter() { - let mut inputs = vec![ - ( - constants::DW_OP_constu, - Operation::UnsignedConstant { value: *value }, - ), - ( - constants::DW_OP_plus_uconst, - Operation::PlusConstant { value: *value }, - ), - ]; - - if *value <= (!0u16).into() { - inputs.push(( - constants::DW_OP_regx, - Operation::Register { - register: Register::from_u64(*value).unwrap(), - }, - )); - } - - if *value <= (!0u32).into() { - inputs.extend(&[ - ( - constants::DW_OP_addrx, - Operation::AddressIndex { - index: DebugAddrIndex(*value as usize), - }, - ), - ( - constants::DW_OP_constx, - Operation::ConstantIndex { - index: DebugAddrIndex(*value as usize), - }, - ), - ]); - } - - // FIXME - if *value < !0u64 / 8 { - inputs.push(( - constants::DW_OP_piece, - Operation::Piece { - size_in_bits: 8 * value, - bit_offset: None, - }, - )); - } - - for item in inputs.iter() { - let (op, ref expect) = *item; - let input = Section::with_endian(Endian::Little) - .D8(op.0) - .uleb(*value) - .get_contents() - .unwrap(); - check_op_parse_simple(&input, expect, encoding); - } - } - } - - #[test] - fn test_op_parse_bregx() { - // Doesn't matter for this test. - let encoding = encoding4(); - - let uvalues = [0, 1, 0x100, !0u16]; - let svalues = [ - -1i64, - 0, - 1, - 0x100, - 0x1eee_eeee, - 0x7fff_ffff_ffff_ffff, - -0x100, - -0x1eee_eeee, - -0x7fff_ffff_ffff_ffff, - ]; - - for v1 in uvalues.iter() { - for v2 in svalues.iter() { - check_op_parse( - |s| s.D8(constants::DW_OP_bregx.0).uleb((*v1).into()).sleb(*v2), - &Operation::RegisterOffset { - register: Register(*v1), - offset: *v2, - base_type: UnitOffset(0), - }, - encoding, - ); - } - } - } - - #[test] - fn test_op_parse_bit_piece() { - // Doesn't matter for this test. - let encoding = encoding4(); - - let values = [0, 1, 0x100, 0x1eee_eeee, 0x7fff_ffff_ffff_ffff, !0u64]; - - for v1 in values.iter() { - for v2 in values.iter() { - let input = Section::with_endian(Endian::Little) - .D8(constants::DW_OP_bit_piece.0) - .uleb(*v1) - .uleb(*v2) - .get_contents() - .unwrap(); - check_op_parse_simple( - &input, - &Operation::Piece { - size_in_bits: *v1, - bit_offset: Some(*v2), - }, - encoding, - ); - } - } - } - - #[test] - fn test_op_parse_implicit_value() { - // Doesn't matter for this test. - let encoding = encoding4(); - - let data = b"hello"; - - check_op_parse( - |s| { - s.D8(constants::DW_OP_implicit_value.0) - .uleb(data.len() as u64) - .append_bytes(&data[..]) - }, - &Operation::ImplicitValue { - data: EndianSlice::new(&data[..], LittleEndian), - }, - encoding, - ); - } - - #[test] - fn test_op_parse_const_type() { - // Doesn't matter for this test. - let encoding = encoding4(); - - let data = b"hello"; - - check_op_parse( - |s| { - s.D8(constants::DW_OP_const_type.0) - .uleb(100) - .D8(data.len() as u8) - .append_bytes(&data[..]) - }, - &Operation::TypedLiteral { - base_type: UnitOffset(100), - value: EndianSlice::new(&data[..], LittleEndian), - }, - encoding, - ); - check_op_parse( - |s| { - s.D8(constants::DW_OP_GNU_const_type.0) - .uleb(100) - .D8(data.len() as u8) - .append_bytes(&data[..]) - }, - &Operation::TypedLiteral { - base_type: UnitOffset(100), - value: EndianSlice::new(&data[..], LittleEndian), - }, - encoding, - ); - } - - #[test] - fn test_op_parse_regval_type() { - // Doesn't matter for this test. - let encoding = encoding4(); - - check_op_parse( - |s| s.D8(constants::DW_OP_regval_type.0).uleb(1).uleb(100), - &Operation::RegisterOffset { - register: Register(1), - offset: 0, - base_type: UnitOffset(100), - }, - encoding, - ); - check_op_parse( - |s| s.D8(constants::DW_OP_GNU_regval_type.0).uleb(1).uleb(100), - &Operation::RegisterOffset { - register: Register(1), - offset: 0, - base_type: UnitOffset(100), - }, - encoding, - ); - } - - #[test] - fn test_op_parse_deref_type() { - // Doesn't matter for this test. - let encoding = encoding4(); - - check_op_parse( - |s| s.D8(constants::DW_OP_deref_type.0).D8(8).uleb(100), - &Operation::Deref { - base_type: UnitOffset(100), - size: 8, - space: false, - }, - encoding, - ); - check_op_parse( - |s| s.D8(constants::DW_OP_GNU_deref_type.0).D8(8).uleb(100), - &Operation::Deref { - base_type: UnitOffset(100), - size: 8, - space: false, - }, - encoding, - ); - check_op_parse( - |s| s.D8(constants::DW_OP_xderef_type.0).D8(8).uleb(100), - &Operation::Deref { - base_type: UnitOffset(100), - size: 8, - space: true, - }, - encoding, - ); - } - - #[test] - fn test_op_convert() { - // Doesn't matter for this test. - let encoding = encoding4(); - - check_op_parse( - |s| s.D8(constants::DW_OP_convert.0).uleb(100), - &Operation::Convert { - base_type: UnitOffset(100), - }, - encoding, - ); - check_op_parse( - |s| s.D8(constants::DW_OP_GNU_convert.0).uleb(100), - &Operation::Convert { - base_type: UnitOffset(100), - }, - encoding, - ); - } - - #[test] - fn test_op_reinterpret() { - // Doesn't matter for this test. - let encoding = encoding4(); - - check_op_parse( - |s| s.D8(constants::DW_OP_reinterpret.0).uleb(100), - &Operation::Reinterpret { - base_type: UnitOffset(100), - }, - encoding, - ); - check_op_parse( - |s| s.D8(constants::DW_OP_GNU_reinterpret.0).uleb(100), - &Operation::Reinterpret { - base_type: UnitOffset(100), - }, - encoding, - ); - } - - #[test] - fn test_op_parse_implicit_pointer() { - for op in &[ - constants::DW_OP_implicit_pointer, - constants::DW_OP_GNU_implicit_pointer, - ] { - check_op_parse( - |s| s.D8(op.0).D32(0x1234_5678).sleb(0x123), - &Operation::ImplicitPointer { - value: DebugInfoOffset(0x1234_5678), - byte_offset: 0x123, - }, - encoding4(), - ); - - check_op_parse( - |s| s.D8(op.0).D64(0x1234_5678).sleb(0x123), - &Operation::ImplicitPointer { - value: DebugInfoOffset(0x1234_5678), - byte_offset: 0x123, - }, - encoding8(), - ); - - check_op_parse( - |s| s.D8(op.0).D64(0x1234_5678).sleb(0x123), - &Operation::ImplicitPointer { - value: DebugInfoOffset(0x1234_5678), - byte_offset: 0x123, - }, - Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 8, - }, - ) - } - } - - #[test] - fn test_op_parse_entry_value() { - for op in &[ - constants::DW_OP_entry_value, - constants::DW_OP_GNU_entry_value, - ] { - let data = b"hello"; - check_op_parse( - |s| s.D8(op.0).uleb(data.len() as u64).append_bytes(&data[..]), - &Operation::EntryValue { - expression: EndianSlice::new(&data[..], LittleEndian), - }, - encoding4(), - ); - } - } - - #[test] - fn test_op_parse_gnu_parameter_ref() { - check_op_parse( - |s| s.D8(constants::DW_OP_GNU_parameter_ref.0).D32(0x1234_5678), - &Operation::ParameterRef { - offset: UnitOffset(0x1234_5678), - }, - encoding4(), - ) - } - - #[test] - fn test_op_wasm() { - // Doesn't matter for this test. - let encoding = encoding4(); - - check_op_parse( - |s| s.D8(constants::DW_OP_WASM_location.0).D8(0).uleb(1000), - &Operation::WasmLocal { index: 1000 }, - encoding, - ); - check_op_parse( - |s| s.D8(constants::DW_OP_WASM_location.0).D8(1).uleb(1000), - &Operation::WasmGlobal { index: 1000 }, - encoding, - ); - check_op_parse( - |s| s.D8(constants::DW_OP_WASM_location.0).D8(2).uleb(1000), - &Operation::WasmStack { index: 1000 }, - encoding, - ); - check_op_parse( - |s| s.D8(constants::DW_OP_WASM_location.0).D8(3).D32(1000), - &Operation::WasmGlobal { index: 1000 }, - encoding, - ); - } - - enum AssemblerEntry { - Op(constants::DwOp), - Mark(u8), - Branch(u8), - U8(u8), - U16(u16), - U32(u32), - U64(u64), - Uleb(u64), - Sleb(u64), - } - - fn assemble(entries: &[AssemblerEntry]) -> Vec<u8> { - let mut result = Vec::new(); - - struct Marker(Option<usize>, Vec<usize>); - - let mut markers = Vec::new(); - for _ in 0..256 { - markers.push(Marker(None, Vec::new())); - } - - fn write(stack: &mut Vec<u8>, index: usize, mut num: u64, nbytes: u8) { - for i in 0..nbytes as usize { - stack[index + i] = (num & 0xff) as u8; - num >>= 8; - } - } - - fn push(stack: &mut Vec<u8>, num: u64, nbytes: u8) { - let index = stack.len(); - for _ in 0..nbytes { - stack.push(0); - } - write(stack, index, num, nbytes); - } - - for item in entries { - match *item { - AssemblerEntry::Op(op) => result.push(op.0), - AssemblerEntry::Mark(num) => { - assert!(markers[num as usize].0.is_none()); - markers[num as usize].0 = Some(result.len()); - } - AssemblerEntry::Branch(num) => { - markers[num as usize].1.push(result.len()); - push(&mut result, 0, 2); - } - AssemblerEntry::U8(num) => result.push(num), - AssemblerEntry::U16(num) => push(&mut result, u64::from(num), 2), - AssemblerEntry::U32(num) => push(&mut result, u64::from(num), 4), - AssemblerEntry::U64(num) => push(&mut result, num, 8), - AssemblerEntry::Uleb(num) => { - leb128::write::unsigned(&mut result, num).unwrap(); - } - AssemblerEntry::Sleb(num) => { - leb128::write::signed(&mut result, num as i64).unwrap(); - } - } - } - - // Update all the branches. - for marker in markers { - if let Some(offset) = marker.0 { - for branch_offset in marker.1 { - let delta = offset.wrapping_sub(branch_offset + 2) as u64; - write(&mut result, branch_offset, delta, 2); - } - } - } - - result - } - - fn check_eval_with_args<F>( - program: &[AssemblerEntry], - expect: Result<&[Piece<EndianSlice<LittleEndian>>]>, - encoding: Encoding, - object_address: Option<u64>, - initial_value: Option<u64>, - max_iterations: Option<u32>, - f: F, - ) where - for<'a> F: Fn( - &mut Evaluation<EndianSlice<'a, LittleEndian>>, - EvaluationResult<EndianSlice<'a, LittleEndian>>, - ) -> Result<EvaluationResult<EndianSlice<'a, LittleEndian>>>, - { - let bytes = assemble(program); - let bytes = EndianSlice::new(&bytes, LittleEndian); - - let mut eval = Evaluation::new(bytes, encoding); - - if let Some(val) = object_address { - eval.set_object_address(val); - } - if let Some(val) = initial_value { - eval.set_initial_value(val); - } - if let Some(val) = max_iterations { - eval.set_max_iterations(val); - } - - let result = match eval.evaluate() { - Err(e) => Err(e), - Ok(r) => f(&mut eval, r), - }; - - match (result, expect) { - (Ok(EvaluationResult::Complete), Ok(pieces)) => { - let vec = eval.result(); - assert_eq!(vec.len(), pieces.len()); - for i in 0..pieces.len() { - assert_eq!(vec[i], pieces[i]); - } - } - (Err(f1), Err(f2)) => { - assert_eq!(f1, f2); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - fn check_eval( - program: &[AssemblerEntry], - expect: Result<&[Piece<EndianSlice<LittleEndian>>]>, - encoding: Encoding, - ) { - check_eval_with_args(program, expect, encoding, None, None, None, |_, result| { - Ok(result) - }); - } - - #[test] - fn test_eval_arith() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - // Indices of marks in the assembly. - let done = 0; - let fail = 1; - - #[rustfmt::skip] - let program = [ - Op(DW_OP_const1u), U8(23), - Op(DW_OP_const1s), U8((-23i8) as u8), - Op(DW_OP_plus), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const2u), U16(23), - Op(DW_OP_const2s), U16((-23i16) as u16), - Op(DW_OP_plus), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const4u), U32(0x1111_2222), - Op(DW_OP_const4s), U32((-0x1111_2222i32) as u32), - Op(DW_OP_plus), - Op(DW_OP_bra), Branch(fail), - - // Plus should overflow. - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_const1u), U8(1), - Op(DW_OP_plus), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_plus_uconst), Uleb(1), - Op(DW_OP_bra), Branch(fail), - - // Minus should underflow. - Op(DW_OP_const1s), U8(0), - Op(DW_OP_const1u), U8(1), - Op(DW_OP_minus), - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_abs), - Op(DW_OP_const1u), U8(1), - Op(DW_OP_minus), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const4u), U32(0xf078_fffe), - Op(DW_OP_const4u), U32(0x0f87_0001), - Op(DW_OP_and), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const4u), U32(0xf078_fffe), - Op(DW_OP_const4u), U32(0xf000_00fe), - Op(DW_OP_and), - Op(DW_OP_const4u), U32(0xf000_00fe), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - // Division is signed. - Op(DW_OP_const1s), U8(0xfe), - Op(DW_OP_const1s), U8(2), - Op(DW_OP_div), - Op(DW_OP_plus_uconst), Uleb(1), - Op(DW_OP_bra), Branch(fail), - - // Mod is unsigned. - Op(DW_OP_const1s), U8(0xfd), - Op(DW_OP_const1s), U8(2), - Op(DW_OP_mod), - Op(DW_OP_neg), - Op(DW_OP_plus_uconst), Uleb(1), - Op(DW_OP_bra), Branch(fail), - - // Overflow is defined for multiplication. - Op(DW_OP_const4u), U32(0x8000_0001), - Op(DW_OP_lit2), - Op(DW_OP_mul), - Op(DW_OP_lit2), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const4u), U32(0xf0f0_f0f0), - Op(DW_OP_const4u), U32(0xf0f0_f0f0), - Op(DW_OP_xor), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const4u), U32(0xf0f0_f0f0), - Op(DW_OP_const4u), U32(0x0f0f_0f0f), - Op(DW_OP_or), - Op(DW_OP_not), - Op(DW_OP_bra), Branch(fail), - - // In 32 bit mode, values are truncated. - Op(DW_OP_const8u), U64(0xffff_ffff_0000_0000), - Op(DW_OP_lit2), - Op(DW_OP_div), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1u), U8(0xff), - Op(DW_OP_lit1), - Op(DW_OP_shl), - Op(DW_OP_const2u), U16(0x1fe), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1u), U8(0xff), - Op(DW_OP_const1u), U8(50), - Op(DW_OP_shl), - Op(DW_OP_bra), Branch(fail), - - // Absurd shift. - Op(DW_OP_const1u), U8(0xff), - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_shl), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_lit1), - Op(DW_OP_shr), - Op(DW_OP_const4u), U32(0x7fff_ffff), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_const1u), U8(0xff), - Op(DW_OP_shr), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_lit1), - Op(DW_OP_shra), - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_const1u), U8(0xff), - Op(DW_OP_shra), - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - // Success. - Op(DW_OP_lit0), - Op(DW_OP_nop), - Op(DW_OP_skip), Branch(done), - - Mark(fail), - Op(DW_OP_lit1), - - Mark(done), - Op(DW_OP_stack_value), - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(0), - }, - }]; - - check_eval(&program, Ok(&result), encoding4()); - } - - #[test] - fn test_eval_arith64() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - // Indices of marks in the assembly. - let done = 0; - let fail = 1; - - #[rustfmt::skip] - let program = [ - Op(DW_OP_const8u), U64(0x1111_2222_3333_4444), - Op(DW_OP_const8s), U64((-0x1111_2222_3333_4444i64) as u64), - Op(DW_OP_plus), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_constu), Uleb(0x1111_2222_3333_4444), - Op(DW_OP_consts), Sleb((-0x1111_2222_3333_4444i64) as u64), - Op(DW_OP_plus), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_lit1), - Op(DW_OP_plus_uconst), Uleb(!0u64), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_lit1), - Op(DW_OP_neg), - Op(DW_OP_not), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), - Op(DW_OP_const1u), U8(63), - Op(DW_OP_shr), - Op(DW_OP_lit1), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), - Op(DW_OP_const1u), U8(62), - Op(DW_OP_shra), - Op(DW_OP_plus_uconst), Uleb(2), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_lit1), - Op(DW_OP_const1u), U8(63), - Op(DW_OP_shl), - Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - // Success. - Op(DW_OP_lit0), - Op(DW_OP_nop), - Op(DW_OP_skip), Branch(done), - - Mark(fail), - Op(DW_OP_lit1), - - Mark(done), - Op(DW_OP_stack_value), - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(0), - }, - }]; - - check_eval(&program, Ok(&result), encoding8()); - } - - #[test] - fn test_eval_compare() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - // Indices of marks in the assembly. - let done = 0; - let fail = 1; - - #[rustfmt::skip] - let program = [ - // Comparisons are signed. - Op(DW_OP_const1s), U8(1), - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_lt), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_const1s), U8(1), - Op(DW_OP_gt), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(1), - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_le), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_const1s), U8(1), - Op(DW_OP_ge), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const1s), U8(0xff), - Op(DW_OP_const1s), U8(1), - Op(DW_OP_eq), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_const4s), U32(1), - Op(DW_OP_const1s), U8(1), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - // Success. - Op(DW_OP_lit0), - Op(DW_OP_nop), - Op(DW_OP_skip), Branch(done), - - Mark(fail), - Op(DW_OP_lit1), - - Mark(done), - Op(DW_OP_stack_value), - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(0), - }, - }]; - - check_eval(&program, Ok(&result), encoding4()); - } - - #[test] - fn test_eval_stack() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - #[rustfmt::skip] - let program = [ - Op(DW_OP_lit17), // -- 17 - Op(DW_OP_dup), // -- 17 17 - Op(DW_OP_over), // -- 17 17 17 - Op(DW_OP_minus), // -- 17 0 - Op(DW_OP_swap), // -- 0 17 - Op(DW_OP_dup), // -- 0 17 17 - Op(DW_OP_plus_uconst), Uleb(1), // -- 0 17 18 - Op(DW_OP_rot), // -- 18 0 17 - Op(DW_OP_pick), U8(2), // -- 18 0 17 18 - Op(DW_OP_pick), U8(3), // -- 18 0 17 18 18 - Op(DW_OP_minus), // -- 18 0 17 0 - Op(DW_OP_drop), // -- 18 0 17 - Op(DW_OP_swap), // -- 18 17 0 - Op(DW_OP_drop), // -- 18 17 - Op(DW_OP_minus), // -- 1 - Op(DW_OP_stack_value), - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(1), - }, - }]; - - check_eval(&program, Ok(&result), encoding4()); - } - - #[test] - fn test_eval_lit_and_reg() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - let mut program = Vec::new(); - program.push(Op(DW_OP_lit0)); - for i in 0..32 { - program.push(Op(DwOp(DW_OP_lit0.0 + i))); - program.push(Op(DwOp(DW_OP_breg0.0 + i))); - program.push(Sleb(u64::from(i))); - program.push(Op(DW_OP_plus)); - program.push(Op(DW_OP_plus)); - } - - program.push(Op(DW_OP_bregx)); - program.push(Uleb(0x1234)); - program.push(Sleb(0x1234)); - program.push(Op(DW_OP_plus)); - - program.push(Op(DW_OP_stack_value)); - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(496), - }, - }]; - - check_eval_with_args( - &program, - Ok(&result), - encoding4(), - None, - None, - None, - |eval, mut result| { - while result != EvaluationResult::Complete { - result = eval.resume_with_register(match result { - EvaluationResult::RequiresRegister { - register, - base_type, - } => { - assert_eq!(base_type, UnitOffset(0)); - Value::Generic(u64::from(register.0).wrapping_neg()) - } - _ => panic!(), - })?; - } - Ok(result) - }, - ); - } - - #[test] - fn test_eval_memory() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - // Indices of marks in the assembly. - let done = 0; - let fail = 1; - - #[rustfmt::skip] - let program = [ - Op(DW_OP_addr), U32(0x7fff_ffff), - Op(DW_OP_deref), - Op(DW_OP_const4u), U32(0xffff_fffc), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_addr), U32(0x7fff_ffff), - Op(DW_OP_deref_size), U8(2), - Op(DW_OP_const4u), U32(0xfffc), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_lit1), - Op(DW_OP_addr), U32(0x7fff_ffff), - Op(DW_OP_xderef), - Op(DW_OP_const4u), U32(0xffff_fffd), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_lit1), - Op(DW_OP_addr), U32(0x7fff_ffff), - Op(DW_OP_xderef_size), U8(2), - Op(DW_OP_const4u), U32(0xfffd), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_lit17), - Op(DW_OP_form_tls_address), - Op(DW_OP_constu), Uleb(!17), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_lit17), - Op(DW_OP_GNU_push_tls_address), - Op(DW_OP_constu), Uleb(!17), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_addrx), Uleb(0x10), - Op(DW_OP_deref), - Op(DW_OP_const4u), U32(0x4040), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - Op(DW_OP_constx), Uleb(17), - Op(DW_OP_form_tls_address), - Op(DW_OP_constu), Uleb(!27), - Op(DW_OP_ne), - Op(DW_OP_bra), Branch(fail), - - // Success. - Op(DW_OP_lit0), - Op(DW_OP_nop), - Op(DW_OP_skip), Branch(done), - - Mark(fail), - Op(DW_OP_lit1), - - Mark(done), - Op(DW_OP_stack_value), - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(0), - }, - }]; - - check_eval_with_args( - &program, - Ok(&result), - encoding4(), - None, - None, - None, - |eval, mut result| { - while result != EvaluationResult::Complete { - result = match result { - EvaluationResult::RequiresMemory { - address, - size, - space, - base_type, - } => { - assert_eq!(base_type, UnitOffset(0)); - let mut v = address << 2; - if let Some(value) = space { - v += value; - } - v &= (1u64 << (8 * size)) - 1; - eval.resume_with_memory(Value::Generic(v))? - } - EvaluationResult::RequiresTls(slot) => eval.resume_with_tls(!slot)?, - EvaluationResult::RequiresRelocatedAddress(address) => { - eval.resume_with_relocated_address(address)? - } - EvaluationResult::RequiresIndexedAddress { index, relocate } => { - if relocate { - eval.resume_with_indexed_address(0x1000 + index.0 as u64)? - } else { - eval.resume_with_indexed_address(10 + index.0 as u64)? - } - } - _ => panic!(), - }; - } - - Ok(result) - }, - ); - } - - #[test] - fn test_eval_register() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - for i in 0..32 { - #[rustfmt::skip] - let program = [ - Op(DwOp(DW_OP_reg0.0 + i)), - // Included only in the "bad" run. - Op(DW_OP_lit23), - ]; - let ok_result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Register { - register: Register(i.into()), - }, - }]; - - check_eval(&program[..1], Ok(&ok_result), encoding4()); - - check_eval( - &program, - Err(Error::InvalidExpressionTerminator(1)), - encoding4(), - ); - } - - #[rustfmt::skip] - let program = [ - Op(DW_OP_regx), Uleb(0x1234) - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Register { - register: Register(0x1234), - }, - }]; - - check_eval(&program, Ok(&result), encoding4()); - } - - #[test] - fn test_eval_context() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - // Test `frame_base` and `call_frame_cfa` callbacks. - #[rustfmt::skip] - let program = [ - Op(DW_OP_fbreg), Sleb((-8i8) as u64), - Op(DW_OP_call_frame_cfa), - Op(DW_OP_plus), - Op(DW_OP_neg), - Op(DW_OP_stack_value) - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(9), - }, - }]; - - check_eval_with_args( - &program, - Ok(&result), - encoding8(), - None, - None, - None, - |eval, result| { - match result { - EvaluationResult::RequiresFrameBase => {} - _ => panic!(), - }; - match eval.resume_with_frame_base(0x0123_4567_89ab_cdef)? { - EvaluationResult::RequiresCallFrameCfa => {} - _ => panic!(), - }; - eval.resume_with_call_frame_cfa(0xfedc_ba98_7654_3210) - }, - ); - - // Test `evaluate_entry_value` callback. - #[rustfmt::skip] - let program = [ - Op(DW_OP_entry_value), Uleb(8), U64(0x1234_5678), - Op(DW_OP_stack_value) - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(0x1234_5678), - }, - }]; - - check_eval_with_args( - &program, - Ok(&result), - encoding8(), - None, - None, - None, - |eval, result| { - let entry_value = match result { - EvaluationResult::RequiresEntryValue(mut expression) => { - expression.0.read_u64()? - } - _ => panic!(), - }; - eval.resume_with_entry_value(Value::Generic(entry_value)) - }, - ); - - // Test missing `object_address` field. - #[rustfmt::skip] - let program = [ - Op(DW_OP_push_object_address), - ]; - - check_eval_with_args( - &program, - Err(Error::InvalidPushObjectAddress), - encoding4(), - None, - None, - None, - |_, _| panic!(), - ); - - // Test `object_address` field. - #[rustfmt::skip] - let program = [ - Op(DW_OP_push_object_address), - Op(DW_OP_stack_value), - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(0xff), - }, - }]; - - check_eval_with_args( - &program, - Ok(&result), - encoding8(), - Some(0xff), - None, - None, - |_, result| Ok(result), - ); - - // Test `initial_value` field. - #[rustfmt::skip] - let program = [ - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Address { - address: 0x1234_5678, - }, - }]; - - check_eval_with_args( - &program, - Ok(&result), - encoding8(), - None, - Some(0x1234_5678), - None, - |_, result| Ok(result), - ); - } - - #[test] - fn test_eval_empty_stack() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - #[rustfmt::skip] - let program = [ - Op(DW_OP_stack_value) - ]; - - check_eval(&program, Err(Error::NotEnoughStackItems), encoding4()); - } - - #[test] - fn test_eval_call() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - #[rustfmt::skip] - let program = [ - Op(DW_OP_lit23), - Op(DW_OP_call2), U16(0x7755), - Op(DW_OP_call4), U32(0x7755_aaee), - Op(DW_OP_call_ref), U32(0x7755_aaee), - Op(DW_OP_stack_value) - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(23), - }, - }]; - - check_eval_with_args( - &program, - Ok(&result), - encoding4(), - None, - None, - None, - |eval, result| { - let buf = EndianSlice::new(&[], LittleEndian); - match result { - EvaluationResult::RequiresAtLocation(_) => {} - _ => panic!(), - }; - - eval.resume_with_at_location(buf)?; - - match result { - EvaluationResult::RequiresAtLocation(_) => {} - _ => panic!(), - }; - - eval.resume_with_at_location(buf)?; - - match result { - EvaluationResult::RequiresAtLocation(_) => {} - _ => panic!(), - }; - - eval.resume_with_at_location(buf) - }, - ); - - // DW_OP_lit2 DW_OP_mul - const SUBR: &[u8] = &[0x32, 0x1e]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { - value: Value::Generic(184), - }, - }]; - - check_eval_with_args( - &program, - Ok(&result), - encoding4(), - None, - None, - None, - |eval, result| { - let buf = EndianSlice::new(SUBR, LittleEndian); - match result { - EvaluationResult::RequiresAtLocation(_) => {} - _ => panic!(), - }; - - eval.resume_with_at_location(buf)?; - - match result { - EvaluationResult::RequiresAtLocation(_) => {} - _ => panic!(), - }; - - eval.resume_with_at_location(buf)?; - - match result { - EvaluationResult::RequiresAtLocation(_) => {} - _ => panic!(), - }; - - eval.resume_with_at_location(buf) - }, - ); - } - - #[test] - fn test_eval_pieces() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - // Example from DWARF 2.6.1.3. - #[rustfmt::skip] - let program = [ - Op(DW_OP_reg3), - Op(DW_OP_piece), Uleb(4), - Op(DW_OP_reg4), - Op(DW_OP_piece), Uleb(2), - ]; - - let result = [ - Piece { - size_in_bits: Some(32), - bit_offset: None, - location: Location::Register { - register: Register(3), - }, - }, - Piece { - size_in_bits: Some(16), - bit_offset: None, - location: Location::Register { - register: Register(4), - }, - }, - ]; - - check_eval(&program, Ok(&result), encoding4()); - - // Example from DWARF 2.6.1.3 (but hacked since dealing with fbreg - // in the tests is a pain). - #[rustfmt::skip] - let program = [ - Op(DW_OP_reg0), - Op(DW_OP_piece), Uleb(4), - Op(DW_OP_piece), Uleb(4), - Op(DW_OP_addr), U32(0x7fff_ffff), - Op(DW_OP_piece), Uleb(4), - ]; - - let result = [ - Piece { - size_in_bits: Some(32), - bit_offset: None, - location: Location::Register { - register: Register(0), - }, - }, - Piece { - size_in_bits: Some(32), - bit_offset: None, - location: Location::Empty, - }, - Piece { - size_in_bits: Some(32), - bit_offset: None, - location: Location::Address { - address: 0x7fff_ffff, - }, - }, - ]; - - check_eval_with_args( - &program, - Ok(&result), - encoding4(), - None, - None, - None, - |eval, mut result| { - while result != EvaluationResult::Complete { - result = match result { - EvaluationResult::RequiresRelocatedAddress(address) => { - eval.resume_with_relocated_address(address)? - } - _ => panic!(), - }; - } - - Ok(result) - }, - ); - - #[rustfmt::skip] - let program = [ - Op(DW_OP_implicit_value), Uleb(5), - U8(23), U8(24), U8(25), U8(26), U8(0), - ]; - - const BYTES: &[u8] = &[23, 24, 25, 26, 0]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Bytes { - value: EndianSlice::new(BYTES, LittleEndian), - }, - }]; - - check_eval(&program, Ok(&result), encoding4()); - - #[rustfmt::skip] - let program = [ - Op(DW_OP_lit7), - Op(DW_OP_stack_value), - Op(DW_OP_bit_piece), Uleb(5), Uleb(0), - Op(DW_OP_bit_piece), Uleb(3), Uleb(0), - ]; - - let result = [ - Piece { - size_in_bits: Some(5), - bit_offset: Some(0), - location: Location::Value { - value: Value::Generic(7), - }, - }, - Piece { - size_in_bits: Some(3), - bit_offset: Some(0), - location: Location::Empty, - }, - ]; - - check_eval(&program, Ok(&result), encoding4()); - - #[rustfmt::skip] - let program = [ - Op(DW_OP_lit7), - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Address { address: 7 }, - }]; - - check_eval(&program, Ok(&result), encoding4()); - - #[rustfmt::skip] - let program = [ - Op(DW_OP_implicit_pointer), U32(0x1234_5678), Sleb(0x123), - ]; - - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::ImplicitPointer { - value: DebugInfoOffset(0x1234_5678), - byte_offset: 0x123, - }, - }]; - - check_eval(&program, Ok(&result), encoding4()); - - #[rustfmt::skip] - let program = [ - Op(DW_OP_reg3), - Op(DW_OP_piece), Uleb(4), - Op(DW_OP_reg4), - ]; - - check_eval(&program, Err(Error::InvalidPiece), encoding4()); - - #[rustfmt::skip] - let program = [ - Op(DW_OP_reg3), - Op(DW_OP_piece), Uleb(4), - Op(DW_OP_lit0), - ]; - - check_eval(&program, Err(Error::InvalidPiece), encoding4()); - } - - #[test] - fn test_eval_max_iterations() { - // It's nice if an operation and its arguments can fit on a single - // line in the test program. - use self::AssemblerEntry::*; - use crate::constants::*; - - #[rustfmt::skip] - let program = [ - Mark(1), - Op(DW_OP_skip), Branch(1), - ]; - - check_eval_with_args( - &program, - Err(Error::TooManyIterations), - encoding4(), - None, - None, - Some(150), - |_, _| panic!(), - ); - } - - #[test] - fn test_eval_typed_stack() { - use self::AssemblerEntry::*; - use crate::constants::*; - - let base_types = [ - ValueType::Generic, - ValueType::U16, - ValueType::U32, - ValueType::F32, - ]; - - // TODO: convert, reinterpret - #[rustfmt::skip] - let tests = [ - ( - &[ - Op(DW_OP_const_type), Uleb(1), U8(2), U16(0x1234), - Op(DW_OP_stack_value), - ][..], - Value::U16(0x1234), - ), - ( - &[ - Op(DW_OP_regval_type), Uleb(0x1234), Uleb(1), - Op(DW_OP_stack_value), - ][..], - Value::U16(0x2340), - ), - ( - &[ - Op(DW_OP_addr), U32(0x7fff_ffff), - Op(DW_OP_deref_type), U8(2), Uleb(1), - Op(DW_OP_stack_value), - ][..], - Value::U16(0xfff0), - ), - ( - &[ - Op(DW_OP_lit1), - Op(DW_OP_addr), U32(0x7fff_ffff), - Op(DW_OP_xderef_type), U8(2), Uleb(1), - Op(DW_OP_stack_value), - ][..], - Value::U16(0xfff1), - ), - ( - &[ - Op(DW_OP_const_type), Uleb(1), U8(2), U16(0x1234), - Op(DW_OP_convert), Uleb(2), - Op(DW_OP_stack_value), - ][..], - Value::U32(0x1234), - ), - ( - &[ - Op(DW_OP_const_type), Uleb(2), U8(4), U32(0x3f80_0000), - Op(DW_OP_reinterpret), Uleb(3), - Op(DW_OP_stack_value), - ][..], - Value::F32(1.0), - ), - ]; - for &(program, value) in &tests { - let result = [Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Value { value }, - }]; - - check_eval_with_args( - program, - Ok(&result), - encoding4(), - None, - None, - None, - |eval, mut result| { - while result != EvaluationResult::Complete { - result = match result { - EvaluationResult::RequiresMemory { - address, - size, - space, - base_type, - } => { - let mut v = address << 4; - if let Some(value) = space { - v += value; - } - v &= (1u64 << (8 * size)) - 1; - let v = Value::from_u64(base_types[base_type.0], v)?; - eval.resume_with_memory(v)? - } - EvaluationResult::RequiresRegister { - register, - base_type, - } => { - let v = Value::from_u64( - base_types[base_type.0], - u64::from(register.0) << 4, - )?; - eval.resume_with_register(v)? - } - EvaluationResult::RequiresBaseType(offset) => { - eval.resume_with_base_type(base_types[offset.0])? - } - EvaluationResult::RequiresRelocatedAddress(address) => { - eval.resume_with_relocated_address(address)? - } - _ => panic!("Unexpected result {:?}", result), - } - } - Ok(result) - }, - ); - } - } -} diff --git a/vendor/gimli/src/read/pubnames.rs b/vendor/gimli/src/read/pubnames.rs deleted file mode 100644 index e8b7e55..0000000 --- a/vendor/gimli/src/read/pubnames.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::common::{DebugInfoOffset, SectionId}; -use crate::endianity::Endianity; -use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser}; -use crate::read::{EndianSlice, Reader, Result, Section, UnitOffset}; - -/// A single parsed pubname. -#[derive(Debug, Clone)] -pub struct PubNamesEntry<R: Reader> { - unit_header_offset: DebugInfoOffset<R::Offset>, - die_offset: UnitOffset<R::Offset>, - name: R, -} - -impl<R: Reader> PubNamesEntry<R> { - /// Returns the name this entry refers to. - pub fn name(&self) -> &R { - &self.name - } - - /// Returns the offset into the .debug_info section for the header of the compilation unit - /// which contains this name. - pub fn unit_header_offset(&self) -> DebugInfoOffset<R::Offset> { - self.unit_header_offset - } - - /// Returns the offset into the compilation unit for the debugging information entry which - /// has this name. - pub fn die_offset(&self) -> UnitOffset<R::Offset> { - self.die_offset - } -} - -impl<R: Reader> PubStuffEntry<R> for PubNamesEntry<R> { - fn new( - die_offset: UnitOffset<R::Offset>, - name: R, - unit_header_offset: DebugInfoOffset<R::Offset>, - ) -> Self { - PubNamesEntry { - unit_header_offset, - die_offset, - name, - } - } -} - -/// The `DebugPubNames` struct represents the DWARF public names information -/// found in the `.debug_pubnames` section. -#[derive(Debug, Clone)] -pub struct DebugPubNames<R: Reader>(DebugLookup<R, PubStuffParser<R, PubNamesEntry<R>>>); - -impl<'input, Endian> DebugPubNames<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugPubNames` instance from the data in the `.debug_pubnames` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_pubnames` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugPubNames, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_pubnames_section_somehow = || &buf; - /// let debug_pubnames = - /// DebugPubNames::new(read_debug_pubnames_section_somehow(), LittleEndian); - /// ``` - pub fn new(debug_pubnames_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_pubnames_section, endian)) - } -} - -impl<R: Reader> DebugPubNames<R> { - /// Iterate the pubnames in the `.debug_pubnames` section. - /// - /// ``` - /// use gimli::{DebugPubNames, EndianSlice, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_pubnames_section_somehow = || &buf; - /// let debug_pubnames = - /// DebugPubNames::new(read_debug_pubnames_section_somehow(), LittleEndian); - /// - /// let mut iter = debug_pubnames.items(); - /// while let Some(pubname) = iter.next().unwrap() { - /// println!("pubname {} found!", pubname.name().to_string_lossy()); - /// } - /// ``` - pub fn items(&self) -> PubNamesEntryIter<R> { - PubNamesEntryIter(self.0.items()) - } -} - -impl<R: Reader> Section<R> for DebugPubNames<R> { - fn id() -> SectionId { - SectionId::DebugPubNames - } - - fn reader(&self) -> &R { - self.0.reader() - } -} - -impl<R: Reader> From<R> for DebugPubNames<R> { - fn from(debug_pubnames_section: R) -> Self { - DebugPubNames(DebugLookup::from(debug_pubnames_section)) - } -} - -/// An iterator over the pubnames from a `.debug_pubnames` section. -/// -/// Can be [used with -/// `FallibleIterator`](./index.html#using-with-fallibleiterator). -#[derive(Debug, Clone)] -pub struct PubNamesEntryIter<R: Reader>(LookupEntryIter<R, PubStuffParser<R, PubNamesEntry<R>>>); - -impl<R: Reader> PubNamesEntryIter<R> { - /// Advance the iterator and return the next pubname. - /// - /// Returns the newly parsed pubname as `Ok(Some(pubname))`. Returns - /// `Ok(None)` when iteration is complete and all pubnames have already been - /// parsed and yielded. If an error occurs while parsing the next pubname, - /// then this error is returned as `Err(e)`, and all subsequent calls return - /// `Ok(None)`. - pub fn next(&mut self) -> Result<Option<PubNamesEntry<R>>> { - self.0.next() - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for PubNamesEntryIter<R> { - type Item = PubNamesEntry<R>; - type Error = crate::read::Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - self.0.next() - } -} diff --git a/vendor/gimli/src/read/pubtypes.rs b/vendor/gimli/src/read/pubtypes.rs deleted file mode 100644 index 6723b42..0000000 --- a/vendor/gimli/src/read/pubtypes.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::common::{DebugInfoOffset, SectionId}; -use crate::endianity::Endianity; -use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser}; -use crate::read::{EndianSlice, Reader, Result, Section, UnitOffset}; - -/// A single parsed pubtype. -#[derive(Debug, Clone)] -pub struct PubTypesEntry<R: Reader> { - unit_header_offset: DebugInfoOffset<R::Offset>, - die_offset: UnitOffset<R::Offset>, - name: R, -} - -impl<R: Reader> PubTypesEntry<R> { - /// Returns the name of the type this entry refers to. - pub fn name(&self) -> &R { - &self.name - } - - /// Returns the offset into the .debug_info section for the header of the compilation unit - /// which contains the type with this name. - pub fn unit_header_offset(&self) -> DebugInfoOffset<R::Offset> { - self.unit_header_offset - } - - /// Returns the offset into the compilation unit for the debugging information entry which - /// the type with this name. - pub fn die_offset(&self) -> UnitOffset<R::Offset> { - self.die_offset - } -} - -impl<R: Reader> PubStuffEntry<R> for PubTypesEntry<R> { - fn new( - die_offset: UnitOffset<R::Offset>, - name: R, - unit_header_offset: DebugInfoOffset<R::Offset>, - ) -> Self { - PubTypesEntry { - unit_header_offset, - die_offset, - name, - } - } -} - -/// The `DebugPubTypes` struct represents the DWARF public types information -/// found in the `.debug_info` section. -#[derive(Debug, Clone)] -pub struct DebugPubTypes<R: Reader>(DebugLookup<R, PubStuffParser<R, PubTypesEntry<R>>>); - -impl<'input, Endian> DebugPubTypes<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugPubTypes` instance from the data in the `.debug_pubtypes` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_pubtypes` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugPubTypes, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_pubtypes_somehow = || &buf; - /// let debug_pubtypes = - /// DebugPubTypes::new(read_debug_pubtypes_somehow(), LittleEndian); - /// ``` - pub fn new(debug_pubtypes_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_pubtypes_section, endian)) - } -} - -impl<R: Reader> DebugPubTypes<R> { - /// Iterate the pubtypes in the `.debug_pubtypes` section. - /// - /// ``` - /// use gimli::{DebugPubTypes, EndianSlice, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_pubtypes_section_somehow = || &buf; - /// let debug_pubtypes = - /// DebugPubTypes::new(read_debug_pubtypes_section_somehow(), LittleEndian); - /// - /// let mut iter = debug_pubtypes.items(); - /// while let Some(pubtype) = iter.next().unwrap() { - /// println!("pubtype {} found!", pubtype.name().to_string_lossy()); - /// } - /// ``` - pub fn items(&self) -> PubTypesEntryIter<R> { - PubTypesEntryIter(self.0.items()) - } -} - -impl<R: Reader> Section<R> for DebugPubTypes<R> { - fn id() -> SectionId { - SectionId::DebugPubTypes - } - - fn reader(&self) -> &R { - self.0.reader() - } -} - -impl<R: Reader> From<R> for DebugPubTypes<R> { - fn from(debug_pubtypes_section: R) -> Self { - DebugPubTypes(DebugLookup::from(debug_pubtypes_section)) - } -} - -/// An iterator over the pubtypes from a `.debug_pubtypes` section. -/// -/// Can be [used with -/// `FallibleIterator`](./index.html#using-with-fallibleiterator). -#[derive(Debug, Clone)] -pub struct PubTypesEntryIter<R: Reader>(LookupEntryIter<R, PubStuffParser<R, PubTypesEntry<R>>>); - -impl<R: Reader> PubTypesEntryIter<R> { - /// Advance the iterator and return the next pubtype. - /// - /// Returns the newly parsed pubtype as `Ok(Some(pubtype))`. Returns - /// `Ok(None)` when iteration is complete and all pubtypes have already been - /// parsed and yielded. If an error occurs while parsing the next pubtype, - /// then this error is returned as `Err(e)`, and all subsequent calls return - /// `Ok(None)`. - pub fn next(&mut self) -> Result<Option<PubTypesEntry<R>>> { - self.0.next() - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for PubTypesEntryIter<R> { - type Item = PubTypesEntry<R>; - type Error = crate::read::Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - self.0.next() - } -} diff --git a/vendor/gimli/src/read/reader.rs b/vendor/gimli/src/read/reader.rs deleted file mode 100644 index e7dd477..0000000 --- a/vendor/gimli/src/read/reader.rs +++ /dev/null @@ -1,502 +0,0 @@ -#[cfg(feature = "read")] -use alloc::borrow::Cow; -use core::convert::TryInto; -use core::fmt::Debug; -use core::hash::Hash; -use core::ops::{Add, AddAssign, Sub}; - -use crate::common::Format; -use crate::endianity::Endianity; -use crate::leb128; -use crate::read::{Error, Result}; - -/// An identifier for an offset within a section reader. -/// -/// This is used for error reporting. The meaning of this value is specific to -/// each reader implementation. The values should be chosen to be unique amongst -/// all readers. If values are not unique then errors may point to the wrong reader. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct ReaderOffsetId(pub u64); - -/// A trait for offsets with a DWARF section. -/// -/// This allows consumers to choose a size that is appropriate for their address space. -pub trait ReaderOffset: - Debug + Copy + Eq + Ord + Hash + Add<Output = Self> + AddAssign + Sub<Output = Self> -{ - /// Convert a u8 to an offset. - fn from_u8(offset: u8) -> Self; - - /// Convert a u16 to an offset. - fn from_u16(offset: u16) -> Self; - - /// Convert an i16 to an offset. - fn from_i16(offset: i16) -> Self; - - /// Convert a u32 to an offset. - fn from_u32(offset: u32) -> Self; - - /// Convert a u64 to an offset. - /// - /// Returns `Error::UnsupportedOffset` if the value is too large. - fn from_u64(offset: u64) -> Result<Self>; - - /// Convert an offset to a u64. - fn into_u64(self) -> u64; - - /// Wrapping (modular) addition. Computes `self + other`. - fn wrapping_add(self, other: Self) -> Self; - - /// Checked subtraction. Computes `self - other`. - fn checked_sub(self, other: Self) -> Option<Self>; -} - -impl ReaderOffset for u64 { - #[inline] - fn from_u8(offset: u8) -> Self { - u64::from(offset) - } - - #[inline] - fn from_u16(offset: u16) -> Self { - u64::from(offset) - } - - #[inline] - fn from_i16(offset: i16) -> Self { - offset as u64 - } - - #[inline] - fn from_u32(offset: u32) -> Self { - u64::from(offset) - } - - #[inline] - fn from_u64(offset: u64) -> Result<Self> { - Ok(offset) - } - - #[inline] - fn into_u64(self) -> u64 { - self - } - - #[inline] - fn wrapping_add(self, other: Self) -> Self { - self.wrapping_add(other) - } - - #[inline] - fn checked_sub(self, other: Self) -> Option<Self> { - self.checked_sub(other) - } -} - -impl ReaderOffset for u32 { - #[inline] - fn from_u8(offset: u8) -> Self { - u32::from(offset) - } - - #[inline] - fn from_u16(offset: u16) -> Self { - u32::from(offset) - } - - #[inline] - fn from_i16(offset: i16) -> Self { - offset as u32 - } - - #[inline] - fn from_u32(offset: u32) -> Self { - offset - } - - #[inline] - fn from_u64(offset64: u64) -> Result<Self> { - let offset = offset64 as u32; - if u64::from(offset) == offset64 { - Ok(offset) - } else { - Err(Error::UnsupportedOffset) - } - } - - #[inline] - fn into_u64(self) -> u64 { - u64::from(self) - } - - #[inline] - fn wrapping_add(self, other: Self) -> Self { - self.wrapping_add(other) - } - - #[inline] - fn checked_sub(self, other: Self) -> Option<Self> { - self.checked_sub(other) - } -} - -impl ReaderOffset for usize { - #[inline] - fn from_u8(offset: u8) -> Self { - offset as usize - } - - #[inline] - fn from_u16(offset: u16) -> Self { - offset as usize - } - - #[inline] - fn from_i16(offset: i16) -> Self { - offset as usize - } - - #[inline] - fn from_u32(offset: u32) -> Self { - offset as usize - } - - #[inline] - fn from_u64(offset64: u64) -> Result<Self> { - let offset = offset64 as usize; - if offset as u64 == offset64 { - Ok(offset) - } else { - Err(Error::UnsupportedOffset) - } - } - - #[inline] - fn into_u64(self) -> u64 { - self as u64 - } - - #[inline] - fn wrapping_add(self, other: Self) -> Self { - self.wrapping_add(other) - } - - #[inline] - fn checked_sub(self, other: Self) -> Option<Self> { - self.checked_sub(other) - } -} - -#[cfg(not(feature = "read"))] -pub(crate) mod seal_if_no_alloc { - #[derive(Debug)] - pub struct Sealed; -} - -/// A trait for reading the data from a DWARF section. -/// -/// All read operations advance the section offset of the reader -/// unless specified otherwise. -/// -/// ## Choosing a `Reader` Implementation -/// -/// `gimli` comes with a few different `Reader` implementations and lets you -/// choose the one that is right for your use case. A `Reader` is essentially a -/// view into the raw bytes that make up some DWARF, but this view might borrow -/// the underlying data or use reference counting ownership, and it might be -/// thread safe or not. -/// -/// | Implementation | Ownership | Thread Safe | Notes | -/// |:------------------|:------------------|:------------|:------| -/// | [`EndianSlice`](./struct.EndianSlice.html) | Borrowed | Yes | Fastest, but requires that all of your code work with borrows. | -/// | [`EndianRcSlice`](./struct.EndianRcSlice.html) | Reference counted | No | Shared ownership via reference counting, which alleviates the borrow restrictions of `EndianSlice` but imposes reference counting increments and decrements. Cannot be sent across threads, because the reference count is not atomic. | -/// | [`EndianArcSlice`](./struct.EndianArcSlice.html) | Reference counted | Yes | The same as `EndianRcSlice`, but uses atomic reference counting, and therefore reference counting operations are slower but `EndianArcSlice`s may be sent across threads. | -/// | [`EndianReader<T>`](./struct.EndianReader.html) | Same as `T` | Same as `T` | Escape hatch for easily defining your own type of `Reader`. | -pub trait Reader: Debug + Clone { - /// The endianity of bytes that are read. - type Endian: Endianity; - - /// The type used for offsets and lengths. - type Offset: ReaderOffset; - - /// Return the endianity of bytes that are read. - fn endian(&self) -> Self::Endian; - - /// Return the number of bytes remaining. - fn len(&self) -> Self::Offset; - - /// Set the number of bytes remaining to zero. - fn empty(&mut self); - - /// Set the number of bytes remaining to the specified length. - fn truncate(&mut self, len: Self::Offset) -> Result<()>; - - /// Return the offset of this reader's data relative to the start of - /// the given base reader's data. - /// - /// May panic if this reader's data is not contained within the given - /// base reader's data. - fn offset_from(&self, base: &Self) -> Self::Offset; - - /// Return an identifier for the current reader offset. - fn offset_id(&self) -> ReaderOffsetId; - - /// Return the offset corresponding to the given `id` if - /// it is associated with this reader. - fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<Self::Offset>; - - /// Find the index of the first occurrence of the given byte. - /// The offset of the reader is not changed. - fn find(&self, byte: u8) -> Result<Self::Offset>; - - /// Discard the specified number of bytes. - fn skip(&mut self, len: Self::Offset) -> Result<()>; - - /// Split a reader in two. - /// - /// A new reader is returned that can be used to read the next - /// `len` bytes, and `self` is advanced so that it reads the remainder. - fn split(&mut self, len: Self::Offset) -> Result<Self>; - - /// This trait cannot be implemented if "read" feature is not enabled. - /// - /// `Reader` trait has a few methods that depend on `alloc` crate. - /// Disallowing `Reader` trait implementation prevents a crate that only depends on - /// "read-core" from being broken if another crate depending on `gimli` enables - /// "read" feature. - #[cfg(not(feature = "read"))] - fn cannot_implement() -> seal_if_no_alloc::Sealed; - - /// Return all remaining data as a clone-on-write slice. - /// - /// The slice will be borrowed where possible, but some readers may - /// always return an owned vector. - /// - /// Does not advance the reader. - #[cfg(feature = "read")] - fn to_slice(&self) -> Result<Cow<[u8]>>; - - /// Convert all remaining data to a clone-on-write string. - /// - /// The string will be borrowed where possible, but some readers may - /// always return an owned string. - /// - /// Does not advance the reader. - /// - /// Returns an error if the data contains invalid characters. - #[cfg(feature = "read")] - fn to_string(&self) -> Result<Cow<str>>; - - /// Convert all remaining data to a clone-on-write string, including invalid characters. - /// - /// The string will be borrowed where possible, but some readers may - /// always return an owned string. - /// - /// Does not advance the reader. - #[cfg(feature = "read")] - fn to_string_lossy(&self) -> Result<Cow<str>>; - - /// Read exactly `buf.len()` bytes into `buf`. - fn read_slice(&mut self, buf: &mut [u8]) -> Result<()>; - - /// Read a u8 array. - #[inline] - fn read_u8_array<A>(&mut self) -> Result<A> - where - A: Sized + Default + AsMut<[u8]>, - { - let mut val = Default::default(); - self.read_slice(<A as AsMut<[u8]>>::as_mut(&mut val))?; - Ok(val) - } - - /// Return true if the number of bytes remaining is zero. - #[inline] - fn is_empty(&self) -> bool { - self.len() == Self::Offset::from_u8(0) - } - - /// Read a u8. - #[inline] - fn read_u8(&mut self) -> Result<u8> { - let a: [u8; 1] = self.read_u8_array()?; - Ok(a[0]) - } - - /// Read an i8. - #[inline] - fn read_i8(&mut self) -> Result<i8> { - let a: [u8; 1] = self.read_u8_array()?; - Ok(a[0] as i8) - } - - /// Read a u16. - #[inline] - fn read_u16(&mut self) -> Result<u16> { - let a: [u8; 2] = self.read_u8_array()?; - Ok(self.endian().read_u16(&a)) - } - - /// Read an i16. - #[inline] - fn read_i16(&mut self) -> Result<i16> { - let a: [u8; 2] = self.read_u8_array()?; - Ok(self.endian().read_i16(&a)) - } - - /// Read a u32. - #[inline] - fn read_u32(&mut self) -> Result<u32> { - let a: [u8; 4] = self.read_u8_array()?; - Ok(self.endian().read_u32(&a)) - } - - /// Read an i32. - #[inline] - fn read_i32(&mut self) -> Result<i32> { - let a: [u8; 4] = self.read_u8_array()?; - Ok(self.endian().read_i32(&a)) - } - - /// Read a u64. - #[inline] - fn read_u64(&mut self) -> Result<u64> { - let a: [u8; 8] = self.read_u8_array()?; - Ok(self.endian().read_u64(&a)) - } - - /// Read an i64. - #[inline] - fn read_i64(&mut self) -> Result<i64> { - let a: [u8; 8] = self.read_u8_array()?; - Ok(self.endian().read_i64(&a)) - } - - /// Read a f32. - #[inline] - fn read_f32(&mut self) -> Result<f32> { - let a: [u8; 4] = self.read_u8_array()?; - Ok(self.endian().read_f32(&a)) - } - - /// Read a f64. - #[inline] - fn read_f64(&mut self) -> Result<f64> { - let a: [u8; 8] = self.read_u8_array()?; - Ok(self.endian().read_f64(&a)) - } - - /// Read an unsigned n-bytes integer u64. - /// - /// # Panics - /// - /// Panics when nbytes < 1 or nbytes > 8 - #[inline] - fn read_uint(&mut self, n: usize) -> Result<u64> { - let mut buf = [0; 8]; - self.read_slice(&mut buf[..n])?; - Ok(self.endian().read_uint(&buf[..n])) - } - - /// Read a null-terminated slice, and return it (excluding the null). - fn read_null_terminated_slice(&mut self) -> Result<Self> { - let idx = self.find(0)?; - let val = self.split(idx)?; - self.skip(Self::Offset::from_u8(1))?; - Ok(val) - } - - /// Skip a LEB128 encoded integer. - fn skip_leb128(&mut self) -> Result<()> { - leb128::read::skip(self) - } - - /// Read an unsigned LEB128 encoded integer. - fn read_uleb128(&mut self) -> Result<u64> { - leb128::read::unsigned(self) - } - - /// Read an unsigned LEB128 encoded u32. - fn read_uleb128_u32(&mut self) -> Result<u32> { - leb128::read::unsigned(self)? - .try_into() - .map_err(|_| Error::BadUnsignedLeb128) - } - - /// Read an unsigned LEB128 encoded u16. - fn read_uleb128_u16(&mut self) -> Result<u16> { - leb128::read::u16(self) - } - - /// Read a signed LEB128 encoded integer. - fn read_sleb128(&mut self) -> Result<i64> { - leb128::read::signed(self) - } - - /// Read an initial length field. - /// - /// This field is encoded as either a 32-bit length or - /// a 64-bit length, and the returned `Format` indicates which. - fn read_initial_length(&mut self) -> Result<(Self::Offset, Format)> { - const MAX_DWARF_32_UNIT_LENGTH: u32 = 0xffff_fff0; - const DWARF_64_INITIAL_UNIT_LENGTH: u32 = 0xffff_ffff; - - let val = self.read_u32()?; - if val < MAX_DWARF_32_UNIT_LENGTH { - Ok((Self::Offset::from_u32(val), Format::Dwarf32)) - } else if val == DWARF_64_INITIAL_UNIT_LENGTH { - let val = self.read_u64().and_then(Self::Offset::from_u64)?; - Ok((val, Format::Dwarf64)) - } else { - Err(Error::UnknownReservedLength) - } - } - - /// Read an address-sized integer, and return it as a `u64`. - fn read_address(&mut self, address_size: u8) -> Result<u64> { - match address_size { - 1 => self.read_u8().map(u64::from), - 2 => self.read_u16().map(u64::from), - 4 => self.read_u32().map(u64::from), - 8 => self.read_u64(), - otherwise => Err(Error::UnsupportedAddressSize(otherwise)), - } - } - - /// Parse a word-sized integer according to the DWARF format. - /// - /// These are always used to encode section offsets or lengths, - /// and so have a type of `Self::Offset`. - fn read_word(&mut self, format: Format) -> Result<Self::Offset> { - match format { - Format::Dwarf32 => self.read_u32().map(Self::Offset::from_u32), - Format::Dwarf64 => self.read_u64().and_then(Self::Offset::from_u64), - } - } - - /// Parse a word-sized section length according to the DWARF format. - #[inline] - fn read_length(&mut self, format: Format) -> Result<Self::Offset> { - self.read_word(format) - } - - /// Parse a word-sized section offset according to the DWARF format. - #[inline] - fn read_offset(&mut self, format: Format) -> Result<Self::Offset> { - self.read_word(format) - } - - /// Parse a section offset of the given size. - /// - /// This is used for `DW_FORM_ref_addr` values in DWARF version 2. - fn read_sized_offset(&mut self, size: u8) -> Result<Self::Offset> { - match size { - 1 => self.read_u8().map(u64::from), - 2 => self.read_u16().map(u64::from), - 4 => self.read_u32().map(u64::from), - 8 => self.read_u64(), - otherwise => Err(Error::UnsupportedOffsetSize(otherwise)), - } - .and_then(Self::Offset::from_u64) - } -} diff --git a/vendor/gimli/src/read/rnglists.rs b/vendor/gimli/src/read/rnglists.rs deleted file mode 100644 index 12e3e04..0000000 --- a/vendor/gimli/src/read/rnglists.rs +++ /dev/null @@ -1,1458 +0,0 @@ -use crate::common::{ - DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, DwarfFileType, Encoding, - RangeListsOffset, SectionId, -}; -use crate::constants; -use crate::endianity::Endianity; -use crate::read::{ - lists::ListsHeader, DebugAddr, EndianSlice, Error, Reader, ReaderOffset, ReaderOffsetId, - Result, Section, -}; - -/// The raw contents of the `.debug_ranges` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugRanges<R> { - pub(crate) section: R, -} - -impl<'input, Endian> DebugRanges<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugRanges` instance from the data in the `.debug_ranges` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_ranges` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugRanges, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_ranges_section_somehow = || &buf; - /// let debug_ranges = DebugRanges::new(read_debug_ranges_section_somehow(), LittleEndian); - /// ``` - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R> Section<R> for DebugRanges<R> { - fn id() -> SectionId { - SectionId::DebugRanges - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugRanges<R> { - fn from(section: R) -> Self { - DebugRanges { section } - } -} - -/// The `DebugRngLists` struct represents the contents of the -/// `.debug_rnglists` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugRngLists<R> { - section: R, -} - -impl<'input, Endian> DebugRngLists<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugRngLists` instance from the data in the - /// `.debug_rnglists` section. - /// - /// It is the caller's responsibility to read the `.debug_rnglists` - /// section and present it as a `&[u8]` slice. That means using some ELF - /// loader on Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugRngLists, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_rnglists_section_somehow = || &buf; - /// let debug_rnglists = - /// DebugRngLists::new(read_debug_rnglists_section_somehow(), LittleEndian); - /// ``` - pub fn new(section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(section, endian)) - } -} - -impl<R> Section<R> for DebugRngLists<R> { - fn id() -> SectionId { - SectionId::DebugRngLists - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugRngLists<R> { - fn from(section: R) -> Self { - DebugRngLists { section } - } -} - -#[allow(unused)] -pub(crate) type RngListsHeader = ListsHeader; - -impl<Offset> DebugRngListsBase<Offset> -where - Offset: ReaderOffset, -{ - /// Returns a `DebugRngListsBase` with the default value of DW_AT_rnglists_base - /// for the given `Encoding` and `DwarfFileType`. - pub fn default_for_encoding_and_file( - encoding: Encoding, - file_type: DwarfFileType, - ) -> DebugRngListsBase<Offset> { - if encoding.version >= 5 && file_type == DwarfFileType::Dwo { - // In .dwo files, the compiler omits the DW_AT_rnglists_base attribute (because there is - // only a single unit in the file) but we must skip past the header, which the attribute - // would normally do for us. - DebugRngListsBase(Offset::from_u8(RngListsHeader::size_for_encoding(encoding))) - } else { - DebugRngListsBase(Offset::from_u8(0)) - } - } -} - -/// The DWARF data found in `.debug_ranges` and `.debug_rnglists` sections. -#[derive(Debug, Default, Clone, Copy)] -pub struct RangeLists<R> { - debug_ranges: DebugRanges<R>, - debug_rnglists: DebugRngLists<R>, -} - -impl<R> RangeLists<R> { - /// Construct a new `RangeLists` instance from the data in the `.debug_ranges` and - /// `.debug_rnglists` sections. - pub fn new(debug_ranges: DebugRanges<R>, debug_rnglists: DebugRngLists<R>) -> RangeLists<R> { - RangeLists { - debug_ranges, - debug_rnglists, - } - } - - /// Return the `.debug_ranges` section. - pub fn debug_ranges(&self) -> &DebugRanges<R> { - &self.debug_ranges - } - - /// Replace the `.debug_ranges` section. - /// - /// This is useful for `.dwo` files when using the GNU split-dwarf extension to DWARF 4. - pub fn set_debug_ranges(&mut self, debug_ranges: DebugRanges<R>) { - self.debug_ranges = debug_ranges; - } - - /// Return the `.debug_rnglists` section. - pub fn debug_rnglists(&self) -> &DebugRngLists<R> { - &self.debug_rnglists - } -} - -impl<T> RangeLists<T> { - /// Create a `RangeLists` that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::RangeLists<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> RangeLists<R> - where - F: FnMut(&'a T) -> R, - { - RangeLists { - debug_ranges: borrow(&self.debug_ranges.section).into(), - debug_rnglists: borrow(&self.debug_rnglists.section).into(), - } - } -} - -impl<R: Reader> RangeLists<R> { - /// Iterate over the `Range` list entries starting at the given offset. - /// - /// The `unit_version` and `address_size` must match the compilation unit that the - /// offset was contained in. - /// - /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the - /// `DW_TAG_compile_unit` entry for the compilation unit that contains this range list. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn ranges( - &self, - offset: RangeListsOffset<R::Offset>, - unit_encoding: Encoding, - base_address: u64, - debug_addr: &DebugAddr<R>, - debug_addr_base: DebugAddrBase<R::Offset>, - ) -> Result<RngListIter<R>> { - Ok(RngListIter::new( - self.raw_ranges(offset, unit_encoding)?, - base_address, - debug_addr.clone(), - debug_addr_base, - )) - } - - /// Iterate over the `RawRngListEntry`ies starting at the given offset. - /// - /// The `unit_encoding` must match the compilation unit that the - /// offset was contained in. - /// - /// This iterator does not perform any processing of the range entries, - /// such as handling base addresses. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn raw_ranges( - &self, - offset: RangeListsOffset<R::Offset>, - unit_encoding: Encoding, - ) -> Result<RawRngListIter<R>> { - let (mut input, format) = if unit_encoding.version <= 4 { - (self.debug_ranges.section.clone(), RangeListsFormat::Bare) - } else { - (self.debug_rnglists.section.clone(), RangeListsFormat::Rle) - }; - input.skip(offset.0)?; - Ok(RawRngListIter::new(input, unit_encoding, format)) - } - - /// Returns the `.debug_rnglists` offset at the given `base` and `index`. - /// - /// The `base` must be the `DW_AT_rnglists_base` value from the compilation unit DIE. - /// This is an offset that points to the first entry following the header. - /// - /// The `index` is the value of a `DW_FORM_rnglistx` attribute. - /// - /// The `unit_encoding` must match the compilation unit that the - /// index was contained in. - pub fn get_offset( - &self, - unit_encoding: Encoding, - base: DebugRngListsBase<R::Offset>, - index: DebugRngListsIndex<R::Offset>, - ) -> Result<RangeListsOffset<R::Offset>> { - let format = unit_encoding.format; - let input = &mut self.debug_rnglists.section.clone(); - input.skip(base.0)?; - input.skip(R::Offset::from_u64( - index.0.into_u64() * u64::from(format.word_size()), - )?)?; - input - .read_offset(format) - .map(|x| RangeListsOffset(base.0 + x)) - } - - /// Call `Reader::lookup_offset_id` for each section, and return the first match. - pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> { - self.debug_ranges - .lookup_offset_id(id) - .or_else(|| self.debug_rnglists.lookup_offset_id(id)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum RangeListsFormat { - /// The bare range list format used before DWARF 5. - Bare, - /// The DW_RLE encoded range list format used in DWARF 5. - Rle, -} - -/// A raw iterator over an address range list. -/// -/// This iterator does not perform any processing of the range entries, -/// such as handling base addresses. -#[derive(Debug)] -pub struct RawRngListIter<R: Reader> { - input: R, - encoding: Encoding, - format: RangeListsFormat, -} - -/// A raw entry in .debug_rnglists -#[derive(Clone, Debug)] -pub enum RawRngListEntry<T> { - /// A range from DWARF version <= 4. - AddressOrOffsetPair { - /// Start of range. May be an address or an offset. - begin: u64, - /// End of range. May be an address or an offset. - end: u64, - }, - /// DW_RLE_base_address - BaseAddress { - /// base address - addr: u64, - }, - /// DW_RLE_base_addressx - BaseAddressx { - /// base address - addr: DebugAddrIndex<T>, - }, - /// DW_RLE_startx_endx - StartxEndx { - /// start of range - begin: DebugAddrIndex<T>, - /// end of range - end: DebugAddrIndex<T>, - }, - /// DW_RLE_startx_length - StartxLength { - /// start of range - begin: DebugAddrIndex<T>, - /// length of range - length: u64, - }, - /// DW_RLE_offset_pair - OffsetPair { - /// start of range - begin: u64, - /// end of range - end: u64, - }, - /// DW_RLE_start_end - StartEnd { - /// start of range - begin: u64, - /// end of range - end: u64, - }, - /// DW_RLE_start_length - StartLength { - /// start of range - begin: u64, - /// length of range - length: u64, - }, -} - -impl<T: ReaderOffset> RawRngListEntry<T> { - /// Parse a range entry from `.debug_rnglists` - fn parse<R: Reader<Offset = T>>( - input: &mut R, - encoding: Encoding, - format: RangeListsFormat, - ) -> Result<Option<Self>> { - Ok(match format { - RangeListsFormat::Bare => { - let range = RawRange::parse(input, encoding.address_size)?; - if range.is_end() { - None - } else if range.is_base_address(encoding.address_size) { - Some(RawRngListEntry::BaseAddress { addr: range.end }) - } else { - Some(RawRngListEntry::AddressOrOffsetPair { - begin: range.begin, - end: range.end, - }) - } - } - RangeListsFormat::Rle => match constants::DwRle(input.read_u8()?) { - constants::DW_RLE_end_of_list => None, - constants::DW_RLE_base_addressx => Some(RawRngListEntry::BaseAddressx { - addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - }), - constants::DW_RLE_startx_endx => Some(RawRngListEntry::StartxEndx { - begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - }), - constants::DW_RLE_startx_length => Some(RawRngListEntry::StartxLength { - begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), - length: input.read_uleb128()?, - }), - constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair { - begin: input.read_uleb128()?, - end: input.read_uleb128()?, - }), - constants::DW_RLE_base_address => Some(RawRngListEntry::BaseAddress { - addr: input.read_address(encoding.address_size)?, - }), - constants::DW_RLE_start_end => Some(RawRngListEntry::StartEnd { - begin: input.read_address(encoding.address_size)?, - end: input.read_address(encoding.address_size)?, - }), - constants::DW_RLE_start_length => Some(RawRngListEntry::StartLength { - begin: input.read_address(encoding.address_size)?, - length: input.read_uleb128()?, - }), - _ => { - return Err(Error::InvalidAddressRange); - } - }, - }) - } -} - -impl<R: Reader> RawRngListIter<R> { - /// Construct a `RawRngListIter`. - fn new(input: R, encoding: Encoding, format: RangeListsFormat) -> RawRngListIter<R> { - RawRngListIter { - input, - encoding, - format, - } - } - - /// Advance the iterator to the next range. - pub fn next(&mut self) -> Result<Option<RawRngListEntry<R::Offset>>> { - if self.input.is_empty() { - return Ok(None); - } - - match RawRngListEntry::parse(&mut self.input, self.encoding, self.format) { - Ok(range) => { - if range.is_none() { - self.input.empty(); - } - Ok(range) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for RawRngListIter<R> { - type Item = RawRngListEntry<R::Offset>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - RawRngListIter::next(self) - } -} - -/// An iterator over an address range list. -/// -/// This iterator internally handles processing of base addresses and different -/// entry types. Thus, it only returns range entries that are valid -/// and already adjusted for the base address. -#[derive(Debug)] -pub struct RngListIter<R: Reader> { - raw: RawRngListIter<R>, - base_address: u64, - debug_addr: DebugAddr<R>, - debug_addr_base: DebugAddrBase<R::Offset>, -} - -impl<R: Reader> RngListIter<R> { - /// Construct a `RngListIter`. - fn new( - raw: RawRngListIter<R>, - base_address: u64, - debug_addr: DebugAddr<R>, - debug_addr_base: DebugAddrBase<R::Offset>, - ) -> RngListIter<R> { - RngListIter { - raw, - base_address, - debug_addr, - debug_addr_base, - } - } - - #[inline] - fn get_address(&self, index: DebugAddrIndex<R::Offset>) -> Result<u64> { - self.debug_addr - .get_address(self.raw.encoding.address_size, self.debug_addr_base, index) - } - - /// Advance the iterator to the next range. - pub fn next(&mut self) -> Result<Option<Range>> { - loop { - let raw_range = match self.raw.next()? { - Some(range) => range, - None => return Ok(None), - }; - - let range = self.convert_raw(raw_range)?; - if range.is_some() { - return Ok(range); - } - } - } - - /// Return the next raw range. - /// - /// The raw range should be passed to `convert_range`. - #[doc(hidden)] - pub fn next_raw(&mut self) -> Result<Option<RawRngListEntry<R::Offset>>> { - self.raw.next() - } - - /// Convert a raw range into a range, and update the state of the iterator. - /// - /// The raw range should have been obtained from `next_raw`. - #[doc(hidden)] - pub fn convert_raw(&mut self, raw_range: RawRngListEntry<R::Offset>) -> Result<Option<Range>> { - let mask = !0 >> (64 - self.raw.encoding.address_size * 8); - let tombstone = if self.raw.encoding.version <= 4 { - mask - 1 - } else { - mask - }; - - let range = match raw_range { - RawRngListEntry::BaseAddress { addr } => { - self.base_address = addr; - return Ok(None); - } - RawRngListEntry::BaseAddressx { addr } => { - self.base_address = self.get_address(addr)?; - return Ok(None); - } - RawRngListEntry::StartxEndx { begin, end } => { - let begin = self.get_address(begin)?; - let end = self.get_address(end)?; - Range { begin, end } - } - RawRngListEntry::StartxLength { begin, length } => { - let begin = self.get_address(begin)?; - let end = begin.wrapping_add(length) & mask; - Range { begin, end } - } - RawRngListEntry::AddressOrOffsetPair { begin, end } - | RawRngListEntry::OffsetPair { begin, end } => { - if self.base_address == tombstone { - return Ok(None); - } - let mut range = Range { begin, end }; - range.add_base_address(self.base_address, self.raw.encoding.address_size); - range - } - RawRngListEntry::StartEnd { begin, end } => Range { begin, end }, - RawRngListEntry::StartLength { begin, length } => { - let end = begin.wrapping_add(length) & mask; - Range { begin, end } - } - }; - - if range.begin == tombstone { - return Ok(None); - } - - if range.begin > range.end { - self.raw.input.empty(); - return Err(Error::InvalidAddressRange); - } - - Ok(Some(range)) - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for RngListIter<R> { - type Item = Range; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - RngListIter::next(self) - } -} - -/// A raw address range from the `.debug_ranges` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct RawRange { - /// The beginning address of the range. - pub begin: u64, - - /// The first address past the end of the range. - pub end: u64, -} - -impl RawRange { - /// Check if this is a range end entry. - #[inline] - pub fn is_end(&self) -> bool { - self.begin == 0 && self.end == 0 - } - - /// Check if this is a base address selection entry. - /// - /// A base address selection entry changes the base address that subsequent - /// range entries are relative to. - #[inline] - pub fn is_base_address(&self, address_size: u8) -> bool { - self.begin == !0 >> (64 - address_size * 8) - } - - /// Parse an address range entry from `.debug_ranges` or `.debug_loc`. - #[inline] - pub fn parse<R: Reader>(input: &mut R, address_size: u8) -> Result<RawRange> { - let begin = input.read_address(address_size)?; - let end = input.read_address(address_size)?; - let range = RawRange { begin, end }; - Ok(range) - } -} - -/// An address range from the `.debug_ranges`, `.debug_rnglists`, or `.debug_aranges` sections. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Range { - /// The beginning address of the range. - pub begin: u64, - - /// The first address past the end of the range. - pub end: u64, -} - -impl Range { - /// Add a base address to this range. - #[inline] - pub(crate) fn add_base_address(&mut self, base_address: u64, address_size: u8) { - let mask = !0 >> (64 - address_size * 8); - self.begin = base_address.wrapping_add(self.begin) & mask; - self.end = base_address.wrapping_add(self.end) & mask; - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::common::Format; - use crate::endianity::LittleEndian; - use crate::test_util::GimliSectionMethods; - use test_assembler::{Endian, Label, LabelMaker, Section}; - - #[test] - fn test_rnglists_32() { - let tombstone = !0u32; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let section = Section::with_endian(Endian::Little) - .L32(0x0300_0000) - .L32(0x0301_0300) - .L32(0x0301_0400) - .L32(0x0301_0500) - .L32(tombstone) - .L32(0x0301_0600); - let buf = section.get_contents().unwrap(); - let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - - let start = Label::new(); - let first = Label::new(); - let size = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // Header - .mark(&start) - .L32(&size) - .L16(encoding.version) - .L8(encoding.address_size) - .L8(0) - .L32(0) - .mark(&first) - // An OffsetPair using the unit base address. - .L8(4).uleb(0x10200).uleb(0x10300) - // A base address selection followed by an OffsetPair. - .L8(5).L32(0x0200_0000) - .L8(4).uleb(0x10400).uleb(0x10500) - // An empty OffsetPair followed by a normal OffsetPair. - .L8(4).uleb(0x10600).uleb(0x10600) - .L8(4).uleb(0x10800).uleb(0x10900) - // A StartEnd - .L8(6).L32(0x201_0a00).L32(0x201_0b00) - // A StartLength - .L8(7).L32(0x201_0c00).uleb(0x100) - // An OffsetPair that starts at 0. - .L8(4).uleb(0).uleb(1) - // An OffsetPair that starts and ends at 0. - .L8(4).uleb(0).uleb(0) - // An OffsetPair that ends at -1. - .L8(5).L32(0) - .L8(4).uleb(0).uleb(0xffff_ffff) - // A BaseAddressx + OffsetPair - .L8(1).uleb(0) - .L8(4).uleb(0x10100).uleb(0x10200) - // A StartxEndx - .L8(2).uleb(1).uleb(2) - // A StartxLength - .L8(3).uleb(3).uleb(0x100) - - // Tombstone entries, all of which should be ignored. - // A BaseAddressx that is a tombstone. - .L8(1).uleb(4) - .L8(4).uleb(0x11100).uleb(0x11200) - // A BaseAddress that is a tombstone. - .L8(5).L32(tombstone) - .L8(4).uleb(0x11300).uleb(0x11400) - // A StartxEndx that is a tombstone. - .L8(2).uleb(4).uleb(5) - // A StartxLength that is a tombstone. - .L8(3).uleb(4).uleb(0x100) - // A StartEnd that is a tombstone. - .L8(6).L32(tombstone).L32(0x201_1500) - // A StartLength that is a tombstone. - .L8(7).L32(tombstone).uleb(0x100) - // A StartEnd (not ignored) - .L8(6).L32(0x201_1600).L32(0x201_1700) - - // A range end. - .L8(0) - // Some extra data. - .L32(0xffff_ffff); - size.set_const((§ion.here() - &start - 4) as u64); - - let buf = section.get_contents().unwrap(); - let debug_ranges = DebugRanges::new(&[], LittleEndian); - let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); - let rnglists = RangeLists::new(debug_ranges, debug_rnglists); - let offset = RangeListsOffset((&first - &start) as usize); - let mut ranges = rnglists - .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) - .unwrap(); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0101_0200, - end: 0x0101_0300, - })) - ); - - // A base address selection followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0400, - end: 0x0201_0500, - })) - ); - - // An empty range followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0600, - end: 0x0201_0600, - })) - ); - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0800, - end: 0x0201_0900, - })) - ); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0a00, - end: 0x0201_0b00, - })) - ); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0c00, - end: 0x0201_0d00, - })) - ); - - // A range that starts at 0. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0200_0000, - end: 0x0200_0001, - })) - ); - - // A range that starts and ends at 0. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0200_0000, - end: 0x0200_0000, - })) - ); - - // A range that ends at -1. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0000_0000, - end: 0xffff_ffff, - })) - ); - - // A BaseAddressx + OffsetPair - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0301_0100, - end: 0x0301_0200, - })) - ); - - // A StartxEndx - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0301_0300, - end: 0x0301_0400, - })) - ); - - // A StartxLength - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0301_0500, - end: 0x0301_0600, - })) - ); - - // A StartEnd range following the tombstones - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_1600, - end: 0x0201_1700, - })) - ); - - // A range end. - assert_eq!(ranges.next(), Ok(None)); - - // An offset at the end of buf. - let mut ranges = rnglists - .ranges( - RangeListsOffset(buf.len()), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(ranges.next(), Ok(None)); - } - - #[test] - fn test_rnglists_64() { - let tombstone = !0u64; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let section = Section::with_endian(Endian::Little) - .L64(0x0300_0000) - .L64(0x0301_0300) - .L64(0x0301_0400) - .L64(0x0301_0500) - .L64(tombstone) - .L64(0x0301_0600); - let buf = section.get_contents().unwrap(); - let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - - let start = Label::new(); - let first = Label::new(); - let size = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // Header - .mark(&start) - .L32(0xffff_ffff) - .L64(&size) - .L16(encoding.version) - .L8(encoding.address_size) - .L8(0) - .L32(0) - .mark(&first) - // An OffsetPair using the unit base address. - .L8(4).uleb(0x10200).uleb(0x10300) - // A base address selection followed by an OffsetPair. - .L8(5).L64(0x0200_0000) - .L8(4).uleb(0x10400).uleb(0x10500) - // An empty OffsetPair followed by a normal OffsetPair. - .L8(4).uleb(0x10600).uleb(0x10600) - .L8(4).uleb(0x10800).uleb(0x10900) - // A StartEnd - .L8(6).L64(0x201_0a00).L64(0x201_0b00) - // A StartLength - .L8(7).L64(0x201_0c00).uleb(0x100) - // An OffsetPair that starts at 0. - .L8(4).uleb(0).uleb(1) - // An OffsetPair that starts and ends at 0. - .L8(4).uleb(0).uleb(0) - // An OffsetPair that ends at -1. - .L8(5).L64(0) - .L8(4).uleb(0).uleb(0xffff_ffff) - // A BaseAddressx + OffsetPair - .L8(1).uleb(0) - .L8(4).uleb(0x10100).uleb(0x10200) - // A StartxEndx - .L8(2).uleb(1).uleb(2) - // A StartxLength - .L8(3).uleb(3).uleb(0x100) - - // Tombstone entries, all of which should be ignored. - // A BaseAddressx that is a tombstone. - .L8(1).uleb(4) - .L8(4).uleb(0x11100).uleb(0x11200) - // A BaseAddress that is a tombstone. - .L8(5).L64(tombstone) - .L8(4).uleb(0x11300).uleb(0x11400) - // A StartxEndx that is a tombstone. - .L8(2).uleb(4).uleb(5) - // A StartxLength that is a tombstone. - .L8(3).uleb(4).uleb(0x100) - // A StartEnd that is a tombstone. - .L8(6).L64(tombstone).L64(0x201_1500) - // A StartLength that is a tombstone. - .L8(7).L64(tombstone).uleb(0x100) - // A StartEnd (not ignored) - .L8(6).L64(0x201_1600).L64(0x201_1700) - - // A range end. - .L8(0) - // Some extra data. - .L32(0xffff_ffff); - size.set_const((§ion.here() - &start - 12) as u64); - - let buf = section.get_contents().unwrap(); - let debug_ranges = DebugRanges::new(&[], LittleEndian); - let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); - let rnglists = RangeLists::new(debug_ranges, debug_rnglists); - let offset = RangeListsOffset((&first - &start) as usize); - let mut ranges = rnglists - .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) - .unwrap(); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0101_0200, - end: 0x0101_0300, - })) - ); - - // A base address selection followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0400, - end: 0x0201_0500, - })) - ); - - // An empty range followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0600, - end: 0x0201_0600, - })) - ); - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0800, - end: 0x0201_0900, - })) - ); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0a00, - end: 0x0201_0b00, - })) - ); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0c00, - end: 0x0201_0d00, - })) - ); - - // A range that starts at 0. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0200_0000, - end: 0x0200_0001, - })) - ); - - // A range that starts and ends at 0. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0200_0000, - end: 0x0200_0000, - })) - ); - - // A range that ends at -1. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0000_0000, - end: 0xffff_ffff, - })) - ); - - // A BaseAddressx + OffsetPair - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0301_0100, - end: 0x0301_0200, - })) - ); - - // A StartxEndx - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0301_0300, - end: 0x0301_0400, - })) - ); - - // A StartxLength - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0301_0500, - end: 0x0301_0600, - })) - ); - - // A StartEnd range following the tombstones - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_1600, - end: 0x0201_1700, - })) - ); - - // A range end. - assert_eq!(ranges.next(), Ok(None)); - - // An offset at the end of buf. - let mut ranges = rnglists - .ranges( - RangeListsOffset(buf.len()), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(ranges.next(), Ok(None)); - } - - #[test] - fn test_raw_range() { - let range = RawRange { - begin: 0, - end: 0xffff_ffff, - }; - assert!(!range.is_end()); - assert!(!range.is_base_address(4)); - assert!(!range.is_base_address(8)); - - let range = RawRange { begin: 0, end: 0 }; - assert!(range.is_end()); - assert!(!range.is_base_address(4)); - assert!(!range.is_base_address(8)); - - let range = RawRange { - begin: 0xffff_ffff, - end: 0, - }; - assert!(!range.is_end()); - assert!(range.is_base_address(4)); - assert!(!range.is_base_address(8)); - - let range = RawRange { - begin: 0xffff_ffff_ffff_ffff, - end: 0, - }; - assert!(!range.is_end()); - assert!(!range.is_base_address(4)); - assert!(range.is_base_address(8)); - } - - #[test] - fn test_ranges_32() { - let tombstone = !0u32 - 1; - let start = Label::new(); - let first = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // A range before the offset. - .mark(&start) - .L32(0x10000).L32(0x10100) - .mark(&first) - // A normal range. - .L32(0x10200).L32(0x10300) - // A base address selection followed by a normal range. - .L32(0xffff_ffff).L32(0x0200_0000) - .L32(0x10400).L32(0x10500) - // An empty range followed by a normal range. - .L32(0x10600).L32(0x10600) - .L32(0x10800).L32(0x10900) - // A range that starts at 0. - .L32(0).L32(1) - // A range that ends at -1. - .L32(0xffff_ffff).L32(0x0000_0000) - .L32(0).L32(0xffff_ffff) - // A normal range with tombstone. - .L32(tombstone).L32(tombstone) - // A base address selection with tombstone followed by a normal range. - .L32(0xffff_ffff).L32(tombstone) - .L32(0x10a00).L32(0x10b00) - // A range end. - .L32(0).L32(0) - // Some extra data. - .L32(0); - - let buf = section.get_contents().unwrap(); - let debug_ranges = DebugRanges::new(&buf, LittleEndian); - let debug_rnglists = DebugRngLists::new(&[], LittleEndian); - let rnglists = RangeLists::new(debug_ranges, debug_rnglists); - let offset = RangeListsOffset((&first - &start) as usize); - let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut ranges = rnglists - .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) - .unwrap(); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0101_0200, - end: 0x0101_0300, - })) - ); - - // A base address selection followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0400, - end: 0x0201_0500, - })) - ); - - // An empty range followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0600, - end: 0x0201_0600, - })) - ); - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0800, - end: 0x0201_0900, - })) - ); - - // A range that starts at 0. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0200_0000, - end: 0x0200_0001, - })) - ); - - // A range that ends at -1. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0000_0000, - end: 0xffff_ffff, - })) - ); - - // A range end. - assert_eq!(ranges.next(), Ok(None)); - - // An offset at the end of buf. - let mut ranges = rnglists - .ranges( - RangeListsOffset(buf.len()), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(ranges.next(), Ok(None)); - } - - #[test] - fn test_ranges_64() { - let tombstone = !0u64 - 1; - let start = Label::new(); - let first = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // A range before the offset. - .mark(&start) - .L64(0x10000).L64(0x10100) - .mark(&first) - // A normal range. - .L64(0x10200).L64(0x10300) - // A base address selection followed by a normal range. - .L64(0xffff_ffff_ffff_ffff).L64(0x0200_0000) - .L64(0x10400).L64(0x10500) - // An empty range followed by a normal range. - .L64(0x10600).L64(0x10600) - .L64(0x10800).L64(0x10900) - // A range that starts at 0. - .L64(0).L64(1) - // A range that ends at -1. - .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000) - .L64(0).L64(0xffff_ffff_ffff_ffff) - // A normal range with tombstone. - .L64(tombstone).L64(tombstone) - // A base address selection with tombstone followed by a normal range. - .L64(0xffff_ffff_ffff_ffff).L64(tombstone) - .L64(0x10a00).L64(0x10b00) - // A range end. - .L64(0).L64(0) - // Some extra data. - .L64(0); - - let buf = section.get_contents().unwrap(); - let debug_ranges = DebugRanges::new(&buf, LittleEndian); - let debug_rnglists = DebugRngLists::new(&[], LittleEndian); - let rnglists = RangeLists::new(debug_ranges, debug_rnglists); - let offset = RangeListsOffset((&first - &start) as usize); - let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - let encoding = Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }; - let mut ranges = rnglists - .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) - .unwrap(); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0101_0200, - end: 0x0101_0300, - })) - ); - - // A base address selection followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0400, - end: 0x0201_0500, - })) - ); - - // An empty range followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0600, - end: 0x0201_0600, - })) - ); - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0201_0800, - end: 0x0201_0900, - })) - ); - - // A range that starts at 0. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0200_0000, - end: 0x0200_0001, - })) - ); - - // A range that ends at -1. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0, - end: 0xffff_ffff_ffff_ffff, - })) - ); - - // A range end. - assert_eq!(ranges.next(), Ok(None)); - - // An offset at the end of buf. - let mut ranges = rnglists - .ranges( - RangeListsOffset(buf.len()), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(ranges.next(), Ok(None)); - } - - #[test] - fn test_ranges_invalid() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - // An invalid range. - .L32(0x20000).L32(0x10000) - // An invalid range after wrapping. - .L32(0x20000).L32(0xff01_0000); - - let buf = section.get_contents().unwrap(); - let debug_ranges = DebugRanges::new(&buf, LittleEndian); - let debug_rnglists = DebugRngLists::new(&[], LittleEndian); - let rnglists = RangeLists::new(debug_ranges, debug_rnglists); - let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); - let debug_addr_base = DebugAddrBase(0); - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - - // An invalid range. - let mut ranges = rnglists - .ranges( - RangeListsOffset(0x0), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); - - // An invalid range after wrapping. - let mut ranges = rnglists - .ranges( - RangeListsOffset(0x8), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) - .unwrap(); - assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); - - // An invalid offset. - match rnglists.ranges( - RangeListsOffset(buf.len() + 1), - encoding, - 0x0100_0000, - debug_addr, - debug_addr_base, - ) { - Err(Error::UnexpectedEof(_)) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - fn test_get_offset() { - for format in vec![Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version: 5, - address_size: 4, - }; - - let zero = Label::new(); - let length = Label::new(); - let start = Label::new(); - let first = Label::new(); - let end = Label::new(); - let mut section = Section::with_endian(Endian::Little) - .mark(&zero) - .initial_length(format, &length, &start) - .D16(encoding.version) - .D8(encoding.address_size) - .D8(0) - .D32(20) - .mark(&first); - for i in 0..20 { - section = section.word(format.word_size(), 1000 + i); - } - section = section.mark(&end); - length.set_const((&end - &start) as u64); - let section = section.get_contents().unwrap(); - - let debug_ranges = DebugRanges::from(EndianSlice::new(&[], LittleEndian)); - let debug_rnglists = DebugRngLists::from(EndianSlice::new(§ion, LittleEndian)); - let ranges = RangeLists::new(debug_ranges, debug_rnglists); - - let base = DebugRngListsBase((&first - &zero) as usize); - assert_eq!( - ranges.get_offset(encoding, base, DebugRngListsIndex(0)), - Ok(RangeListsOffset(base.0 + 1000)) - ); - assert_eq!( - ranges.get_offset(encoding, base, DebugRngListsIndex(19)), - Ok(RangeListsOffset(base.0 + 1019)) - ); - } - } -} diff --git a/vendor/gimli/src/read/str.rs b/vendor/gimli/src/read/str.rs deleted file mode 100644 index c6b87d8..0000000 --- a/vendor/gimli/src/read/str.rs +++ /dev/null @@ -1,321 +0,0 @@ -use crate::common::{ - DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType, - Encoding, SectionId, -}; -use crate::endianity::Endianity; -use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section}; -use crate::Format; - -/// The `DebugStr` struct represents the DWARF strings -/// found in the `.debug_str` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugStr<R> { - debug_str_section: R, -} - -impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugStr` instance from the data in the `.debug_str` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_str` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugStr, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_str_section_somehow = || &buf; - /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian); - /// ``` - pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_str_section, endian)) - } -} - -impl<R: Reader> DebugStr<R> { - /// Lookup a string from the `.debug_str` section by DebugStrOffset. - /// - /// ``` - /// use gimli::{DebugStr, DebugStrOffset, LittleEndian}; - /// - /// # let buf = [0x01, 0x02, 0x00]; - /// # let offset = DebugStrOffset(0); - /// # let read_debug_str_section_somehow = || &buf; - /// # let debug_str_offset_somehow = || offset; - /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian); - /// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow())); - /// ``` - pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> { - let input = &mut self.debug_str_section.clone(); - input.skip(offset.0)?; - input.read_null_terminated_slice() - } -} - -impl<T> DebugStr<T> { - /// Create a `DebugStr` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugStr<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.debug_str_section).into() - } -} - -impl<R> Section<R> for DebugStr<R> { - fn id() -> SectionId { - SectionId::DebugStr - } - - fn reader(&self) -> &R { - &self.debug_str_section - } -} - -impl<R> From<R> for DebugStr<R> { - fn from(debug_str_section: R) -> Self { - DebugStr { debug_str_section } - } -} - -/// The raw contents of the `.debug_str_offsets` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugStrOffsets<R> { - section: R, -} - -impl<R: Reader> DebugStrOffsets<R> { - // TODO: add an iterator over the sets of entries in the section. - // This is not needed for common usage of the section though. - - /// Returns the `.debug_str` offset at the given `base` and `index`. - /// - /// A set of entries in the `.debug_str_offsets` section consists of a header - /// followed by a series of string table offsets. - /// - /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE. - /// This is an offset that points to the first entry following the header. - /// - /// The `index` is the value of a `DW_FORM_strx` attribute. - /// - /// The `format` must be the DWARF format of the compilation unit. This format must - /// match the header. However, note that we do not parse the header to validate this, - /// since locating the header is unreliable, and the GNU extensions do not emit it. - pub fn get_str_offset( - &self, - format: Format, - base: DebugStrOffsetsBase<R::Offset>, - index: DebugStrOffsetsIndex<R::Offset>, - ) -> Result<DebugStrOffset<R::Offset>> { - let input = &mut self.section.clone(); - input.skip(base.0)?; - input.skip(R::Offset::from_u64( - index.0.into_u64() * u64::from(format.word_size()), - )?)?; - input.read_offset(format).map(DebugStrOffset) - } -} - -impl<T> DebugStrOffsets<T> { - /// Create a `DebugStrOffsets` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugStrOffsets<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.section).into() - } -} - -impl<R> Section<R> for DebugStrOffsets<R> { - fn id() -> SectionId { - SectionId::DebugStrOffsets - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugStrOffsets<R> { - fn from(section: R) -> Self { - DebugStrOffsets { section } - } -} - -impl<Offset> DebugStrOffsetsBase<Offset> -where - Offset: ReaderOffset, -{ - /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base - /// for the given `Encoding` and `DwarfFileType`. - pub fn default_for_encoding_and_file( - encoding: Encoding, - file_type: DwarfFileType, - ) -> DebugStrOffsetsBase<Offset> { - if encoding.version >= 5 && file_type == DwarfFileType::Dwo { - // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is - // only a single unit in the file) but we must skip past the header, which the attribute - // would normally do for us. - // initial_length_size + version + 2 bytes of padding. - DebugStrOffsetsBase(Offset::from_u8( - encoding.format.initial_length_size() + 2 + 2, - )) - } else { - DebugStrOffsetsBase(Offset::from_u8(0)) - } - } -} - -/// The `DebugLineStr` struct represents the DWARF strings -/// found in the `.debug_line_str` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugLineStr<R> { - section: R, -} - -impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_line_str` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugLineStr, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_line_str_section_somehow = || &buf; - /// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian); - /// ``` - pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_line_str_section, endian)) - } -} - -impl<R: Reader> DebugLineStr<R> { - /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset. - pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> { - let input = &mut self.section.clone(); - input.skip(offset.0)?; - input.read_null_terminated_slice() - } -} - -impl<T> DebugLineStr<T> { - /// Create a `DebugLineStr` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugLineStr<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.section).into() - } -} - -impl<R> Section<R> for DebugLineStr<R> { - fn id() -> SectionId { - SectionId::DebugLineStr - } - - fn reader(&self) -> &R { - &self.section - } -} - -impl<R> From<R> for DebugLineStr<R> { - fn from(section: R) -> Self { - DebugLineStr { section } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_util::GimliSectionMethods; - use crate::LittleEndian; - use test_assembler::{Endian, Label, LabelMaker, Section}; - - #[test] - fn test_get_str_offset() { - for format in vec![Format::Dwarf32, Format::Dwarf64] { - let zero = Label::new(); - let length = Label::new(); - let start = Label::new(); - let first = Label::new(); - let end = Label::new(); - let mut section = Section::with_endian(Endian::Little) - .mark(&zero) - .initial_length(format, &length, &start) - .D16(5) - .D16(0) - .mark(&first); - for i in 0..20 { - section = section.word(format.word_size(), 1000 + i); - } - section = section.mark(&end); - length.set_const((&end - &start) as u64); - - let section = section.get_contents().unwrap(); - let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian)); - let base = DebugStrOffsetsBase((&first - &zero) as usize); - - assert_eq!( - debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)), - Ok(DebugStrOffset(1000)) - ); - assert_eq!( - debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)), - Ok(DebugStrOffset(1019)) - ); - } - } -} diff --git a/vendor/gimli/src/read/unit.rs b/vendor/gimli/src/read/unit.rs deleted file mode 100644 index d799f0f..0000000 --- a/vendor/gimli/src/read/unit.rs +++ /dev/null @@ -1,6139 +0,0 @@ -//! Functions for parsing DWARF `.debug_info` and `.debug_types` sections. - -use core::cell::Cell; -use core::ops::{Range, RangeFrom, RangeTo}; -use core::{u16, u8}; - -use crate::common::{ - DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset, - DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset, - DebugMacroOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, - DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwoId, Encoding, Format, - LocationListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset, -}; -use crate::constants; -use crate::endianity::Endianity; -use crate::read::abbrev::get_attribute_size; -use crate::read::{ - Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error, - Expression, Reader, ReaderOffset, Result, Section, UnitOffset, -}; - -impl<T: ReaderOffset> DebugTypesOffset<T> { - /// Convert an offset to be relative to the start of the given unit, - /// instead of relative to the start of the .debug_types section. - /// Returns `None` if the offset is not within the unit entries. - pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>> - where - R: Reader<Offset = T>, - { - let unit_offset = unit.offset().as_debug_types_offset()?; - let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?); - if !unit.is_valid_offset(offset) { - return None; - } - Some(offset) - } -} - -impl<T: ReaderOffset> DebugInfoOffset<T> { - /// Convert an offset to be relative to the start of the given unit, - /// instead of relative to the start of the .debug_info section. - /// Returns `None` if the offset is not within this unit entries. - pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>> - where - R: Reader<Offset = T>, - { - let unit_offset = unit.offset().as_debug_info_offset()?; - let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?); - if !unit.is_valid_offset(offset) { - return None; - } - Some(offset) - } -} - -impl<T: ReaderOffset> UnitOffset<T> { - /// Convert an offset to be relative to the start of the .debug_info section, - /// instead of relative to the start of the given unit. Returns None if the - /// provided unit lives in the .debug_types section. - pub fn to_debug_info_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugInfoOffset<T>> - where - R: Reader<Offset = T>, - { - let unit_offset = unit.offset().as_debug_info_offset()?; - Some(DebugInfoOffset(unit_offset.0 + self.0)) - } - - /// Convert an offset to be relative to the start of the .debug_types section, - /// instead of relative to the start of the given unit. Returns None if the - /// provided unit lives in the .debug_info section. - pub fn to_debug_types_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugTypesOffset<T>> - where - R: Reader<Offset = T>, - { - let unit_offset = unit.offset().as_debug_types_offset()?; - Some(DebugTypesOffset(unit_offset.0 + self.0)) - } -} - -/// The `DebugInfo` struct represents the DWARF debugging information found in -/// the `.debug_info` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugInfo<R> { - debug_info_section: R, -} - -impl<'input, Endian> DebugInfo<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugInfo` instance from the data in the `.debug_info` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_info` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugInfo, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_info_section_somehow = || &buf; - /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); - /// ``` - pub fn new(debug_info_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_info_section, endian)) - } -} - -impl<R: Reader> DebugInfo<R> { - /// Iterate the units in this `.debug_info` section. - /// - /// ``` - /// use gimli::{DebugInfo, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_info_section_somehow = || &buf; - /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); - /// - /// let mut iter = debug_info.units(); - /// while let Some(unit) = iter.next().unwrap() { - /// println!("unit's length is {}", unit.unit_length()); - /// } - /// ``` - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn units(&self) -> DebugInfoUnitHeadersIter<R> { - DebugInfoUnitHeadersIter { - input: self.debug_info_section.clone(), - offset: DebugInfoOffset(R::Offset::from_u8(0)), - } - } - - /// Get the UnitHeader located at offset from this .debug_info section. - /// - /// - pub fn header_from_offset(&self, offset: DebugInfoOffset<R::Offset>) -> Result<UnitHeader<R>> { - let input = &mut self.debug_info_section.clone(); - input.skip(offset.0)?; - parse_unit_header(input, offset.into()) - } -} - -impl<T> DebugInfo<T> { - /// Create a `DebugInfo` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugInfo<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugInfo<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.debug_info_section).into() - } -} - -impl<R> Section<R> for DebugInfo<R> { - fn id() -> SectionId { - SectionId::DebugInfo - } - - fn reader(&self) -> &R { - &self.debug_info_section - } -} - -impl<R> From<R> for DebugInfo<R> { - fn from(debug_info_section: R) -> Self { - DebugInfo { debug_info_section } - } -} - -/// An iterator over the units of a .debug_info section. -/// -/// See the [documentation on -/// `DebugInfo::units`](./struct.DebugInfo.html#method.units) for more detail. -#[derive(Clone, Debug)] -pub struct DebugInfoUnitHeadersIter<R: Reader> { - input: R, - offset: DebugInfoOffset<R::Offset>, -} - -impl<R: Reader> DebugInfoUnitHeadersIter<R> { - /// Advance the iterator to the next unit header. - pub fn next(&mut self) -> Result<Option<UnitHeader<R>>> { - if self.input.is_empty() { - Ok(None) - } else { - let len = self.input.len(); - match parse_unit_header(&mut self.input, self.offset.into()) { - Ok(header) => { - self.offset.0 += len - self.input.len(); - Ok(Some(header)) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for DebugInfoUnitHeadersIter<R> { - type Item = UnitHeader<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - DebugInfoUnitHeadersIter::next(self) - } -} - -/// Parse the unit type from the unit header. -fn parse_unit_type<R: Reader>(input: &mut R) -> Result<constants::DwUt> { - let val = input.read_u8()?; - Ok(constants::DwUt(val)) -} - -/// Parse the `debug_abbrev_offset` in the compilation unit header. -fn parse_debug_abbrev_offset<R: Reader>( - input: &mut R, - format: Format, -) -> Result<DebugAbbrevOffset<R::Offset>> { - input.read_offset(format).map(DebugAbbrevOffset) -} - -/// Parse the `debug_info_offset` in the arange header. -pub(crate) fn parse_debug_info_offset<R: Reader>( - input: &mut R, - format: Format, -) -> Result<DebugInfoOffset<R::Offset>> { - input.read_offset(format).map(DebugInfoOffset) -} - -/// This enum specifies the type of the unit and any type -/// specific data carried in the header (e.g. the type -/// signature/type offset of a type unit). -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum UnitType<Offset> -where - Offset: ReaderOffset, -{ - /// In DWARF5, a unit with type `DW_UT_compile`. In previous DWARF versions, - /// any unit appearing in the .debug_info section. - Compilation, - /// In DWARF5, a unit with type `DW_UT_type`. In DWARF4, any unit appearing - /// in the .debug_types section. - Type { - /// The unique type signature for this type unit. - type_signature: DebugTypeSignature, - /// The offset within this type unit where the type is defined. - type_offset: UnitOffset<Offset>, - }, - /// A unit with type `DW_UT_partial`. The root DIE of this unit should be a - /// `DW_TAG_partial_unit`. - Partial, - /// A unit with type `DW_UT_skeleton`. The enclosed dwo_id can be used to - /// link this with the corresponding `SplitCompilation` unit in a dwo file. - /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead - /// be a `Compilation` unit with the dwo_id present as an attribute on the - /// root DIE. - Skeleton(DwoId), - /// A unit with type `DW_UT_split_compile`. The enclosed dwo_id can be used to - /// link this with the corresponding `Skeleton` unit in the original binary. - /// NB: The non-standard GNU split DWARF extension to DWARF 4 will instead - /// be a `Compilation` unit with the dwo_id present as an attribute on the - /// root DIE. - SplitCompilation(DwoId), - /// A unit with type `DW_UT_split_type`. A split type unit is identical to a - /// conventional type unit except for the section in which it appears. - SplitType { - /// The unique type signature for this type unit. - type_signature: DebugTypeSignature, - /// The offset within this type unit where the type is defined. - type_offset: UnitOffset<Offset>, - }, -} - -impl<Offset> UnitType<Offset> -where - Offset: ReaderOffset, -{ - // TODO: This will be used by the DWARF writing code once it - // supports unit types other than simple compilation units. - #[allow(unused)] - pub(crate) fn dw_ut(&self) -> constants::DwUt { - match self { - UnitType::Compilation => constants::DW_UT_compile, - UnitType::Type { .. } => constants::DW_UT_type, - UnitType::Partial => constants::DW_UT_partial, - UnitType::Skeleton(_) => constants::DW_UT_skeleton, - UnitType::SplitCompilation(_) => constants::DW_UT_split_compile, - UnitType::SplitType { .. } => constants::DW_UT_split_type, - } - } -} - -/// The common fields for the headers of compilation units and -/// type units. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct UnitHeader<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - encoding: Encoding, - unit_length: Offset, - unit_type: UnitType<Offset>, - debug_abbrev_offset: DebugAbbrevOffset<Offset>, - unit_offset: UnitSectionOffset<Offset>, - entries_buf: R, -} - -/// Static methods. -impl<R, Offset> UnitHeader<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Construct a new `UnitHeader`. - pub fn new( - encoding: Encoding, - unit_length: Offset, - unit_type: UnitType<Offset>, - debug_abbrev_offset: DebugAbbrevOffset<Offset>, - unit_offset: UnitSectionOffset<Offset>, - entries_buf: R, - ) -> Self { - UnitHeader { - encoding, - unit_length, - unit_type, - debug_abbrev_offset, - unit_offset, - entries_buf, - } - } -} - -/// Instance methods. -impl<R, Offset> UnitHeader<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Get the offset of this unit within its section. - pub fn offset(&self) -> UnitSectionOffset<Offset> { - self.unit_offset - } - - /// Return the serialized size of the common unit header for the given - /// DWARF format. - pub fn size_of_header(&self) -> usize { - let unit_length_size = self.encoding.format.initial_length_size() as usize; - let version_size = 2; - let debug_abbrev_offset_size = self.encoding.format.word_size() as usize; - let address_size_size = 1; - let unit_type_size = if self.encoding.version == 5 { 1 } else { 0 }; - let type_specific_size = match self.unit_type { - UnitType::Compilation | UnitType::Partial => 0, - UnitType::Type { .. } | UnitType::SplitType { .. } => { - let type_signature_size = 8; - let type_offset_size = self.encoding.format.word_size() as usize; - type_signature_size + type_offset_size - } - UnitType::Skeleton(_) | UnitType::SplitCompilation(_) => 8, - }; - - unit_length_size - + version_size - + debug_abbrev_offset_size - + address_size_size - + unit_type_size - + type_specific_size - } - - /// Get the length of the debugging info for this compilation unit, not - /// including the byte length of the encoded length itself. - pub fn unit_length(&self) -> Offset { - self.unit_length - } - - /// Get the length of the debugging info for this compilation unit, - /// including the byte length of the encoded length itself. - pub fn length_including_self(&self) -> Offset { - Offset::from_u8(self.format().initial_length_size()) + self.unit_length - } - - /// Return the encoding parameters for this unit. - pub fn encoding(&self) -> Encoding { - self.encoding - } - - /// Get the DWARF version of the debugging info for this compilation unit. - pub fn version(&self) -> u16 { - self.encoding.version - } - - /// Get the UnitType of this unit. - pub fn type_(&self) -> UnitType<Offset> { - self.unit_type - } - - /// The offset into the `.debug_abbrev` section for this compilation unit's - /// debugging information entries' abbreviations. - pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset<Offset> { - self.debug_abbrev_offset - } - - /// The size of addresses (in bytes) in this compilation unit. - pub fn address_size(&self) -> u8 { - self.encoding.address_size - } - - /// Whether this compilation unit is encoded in 64- or 32-bit DWARF. - pub fn format(&self) -> Format { - self.encoding.format - } - - /// The serialized size of the header for this compilation unit. - pub fn header_size(&self) -> Offset { - self.length_including_self() - self.entries_buf.len() - } - - pub(crate) fn is_valid_offset(&self, offset: UnitOffset<Offset>) -> bool { - let size_of_header = self.header_size(); - if offset.0 < size_of_header { - return false; - } - - let relative_to_entries_buf = offset.0 - size_of_header; - relative_to_entries_buf < self.entries_buf.len() - } - - /// Get the underlying bytes for the supplied range. - pub fn range(&self, idx: Range<UnitOffset<Offset>>) -> Result<R> { - if !self.is_valid_offset(idx.start) { - return Err(Error::OffsetOutOfBounds); - } - if !self.is_valid_offset(idx.end) { - return Err(Error::OffsetOutOfBounds); - } - assert!(idx.start <= idx.end); - let size_of_header = self.header_size(); - let start = idx.start.0 - size_of_header; - let end = idx.end.0 - size_of_header; - let mut input = self.entries_buf.clone(); - input.skip(start)?; - input.truncate(end - start)?; - Ok(input) - } - - /// Get the underlying bytes for the supplied range. - pub fn range_from(&self, idx: RangeFrom<UnitOffset<Offset>>) -> Result<R> { - if !self.is_valid_offset(idx.start) { - return Err(Error::OffsetOutOfBounds); - } - let start = idx.start.0 - self.header_size(); - let mut input = self.entries_buf.clone(); - input.skip(start)?; - Ok(input) - } - - /// Get the underlying bytes for the supplied range. - pub fn range_to(&self, idx: RangeTo<UnitOffset<Offset>>) -> Result<R> { - if !self.is_valid_offset(idx.end) { - return Err(Error::OffsetOutOfBounds); - } - let end = idx.end.0 - self.header_size(); - let mut input = self.entries_buf.clone(); - input.truncate(end)?; - Ok(input) - } - - /// Read the `DebuggingInformationEntry` at the given offset. - pub fn entry<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: UnitOffset<Offset>, - ) -> Result<DebuggingInformationEntry<'abbrev, 'me, R>> { - let mut input = self.range_from(offset..)?; - let entry = DebuggingInformationEntry::parse(&mut input, self, abbreviations)?; - entry.ok_or(Error::NoEntryAtGivenOffset) - } - - /// Navigate this unit's `DebuggingInformationEntry`s. - pub fn entries<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - ) -> EntriesCursor<'abbrev, 'me, R> { - EntriesCursor { - unit: self, - input: self.entries_buf.clone(), - abbreviations, - cached_current: None, - delta_depth: 0, - } - } - - /// Navigate this compilation unit's `DebuggingInformationEntry`s - /// starting at the given offset. - pub fn entries_at_offset<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: UnitOffset<Offset>, - ) -> Result<EntriesCursor<'abbrev, 'me, R>> { - let input = self.range_from(offset..)?; - Ok(EntriesCursor { - unit: self, - input, - abbreviations, - cached_current: None, - delta_depth: 0, - }) - } - - /// Navigate this unit's `DebuggingInformationEntry`s as a tree - /// starting at the given offset. - pub fn entries_tree<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: Option<UnitOffset<Offset>>, - ) -> Result<EntriesTree<'abbrev, 'me, R>> { - let input = match offset { - Some(offset) => self.range_from(offset..)?, - None => self.entries_buf.clone(), - }; - Ok(EntriesTree::new(input, self, abbreviations)) - } - - /// Read the raw data that defines the Debugging Information Entries. - pub fn entries_raw<'me, 'abbrev>( - &'me self, - abbreviations: &'abbrev Abbreviations, - offset: Option<UnitOffset<Offset>>, - ) -> Result<EntriesRaw<'abbrev, 'me, R>> { - let input = match offset { - Some(offset) => self.range_from(offset..)?, - None => self.entries_buf.clone(), - }; - Ok(EntriesRaw { - input, - unit: self, - abbreviations, - depth: 0, - }) - } - - /// Parse this unit's abbreviations. - pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev<R>) -> Result<Abbreviations> { - debug_abbrev.abbreviations(self.debug_abbrev_offset()) - } -} - -/// Parse a unit header. -fn parse_unit_header<R, Offset>( - input: &mut R, - unit_offset: UnitSectionOffset<Offset>, -) -> Result<UnitHeader<R>> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - let (unit_length, format) = input.read_initial_length()?; - let mut rest = input.split(unit_length)?; - - let version = rest.read_u16()?; - let abbrev_offset; - let address_size; - let unit_type; - // DWARF 1 was very different, and is obsolete, so isn't supported by this - // reader. - if 2 <= version && version <= 4 { - abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?; - address_size = rest.read_u8()?; - // Before DWARF5, all units in the .debug_info section are compilation - // units, and all units in the .debug_types section are type units. - unit_type = match unit_offset { - UnitSectionOffset::DebugInfoOffset(_) => constants::DW_UT_compile, - UnitSectionOffset::DebugTypesOffset(_) => constants::DW_UT_type, - }; - } else if version == 5 { - unit_type = parse_unit_type(&mut rest)?; - address_size = rest.read_u8()?; - abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?; - } else { - return Err(Error::UnknownVersion(u64::from(version))); - } - let encoding = Encoding { - format, - version, - address_size, - }; - - // Parse any data specific to this type of unit. - let unit_type = match unit_type { - constants::DW_UT_compile => UnitType::Compilation, - constants::DW_UT_type => { - let type_signature = parse_type_signature(&mut rest)?; - let type_offset = parse_type_offset(&mut rest, format)?; - UnitType::Type { - type_signature, - type_offset, - } - } - constants::DW_UT_partial => UnitType::Partial, - constants::DW_UT_skeleton => { - let dwo_id = parse_dwo_id(&mut rest)?; - UnitType::Skeleton(dwo_id) - } - constants::DW_UT_split_compile => { - let dwo_id = parse_dwo_id(&mut rest)?; - UnitType::SplitCompilation(dwo_id) - } - constants::DW_UT_split_type => { - let type_signature = parse_type_signature(&mut rest)?; - let type_offset = parse_type_offset(&mut rest, format)?; - UnitType::SplitType { - type_signature, - type_offset, - } - } - _ => return Err(Error::UnsupportedUnitType), - }; - - Ok(UnitHeader::new( - encoding, - unit_length, - unit_type, - abbrev_offset, - unit_offset, - rest, - )) -} - -/// Parse a dwo_id from a header -fn parse_dwo_id<R: Reader>(input: &mut R) -> Result<DwoId> { - Ok(DwoId(input.read_u64()?)) -} - -/// A Debugging Information Entry (DIE). -/// -/// DIEs have a set of attributes and optionally have children DIEs as well. -#[derive(Clone, Debug)] -pub struct DebuggingInformationEntry<'abbrev, 'unit, R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - offset: UnitOffset<Offset>, - attrs_slice: R, - attrs_len: Cell<Option<Offset>>, - abbrev: &'abbrev Abbreviation, - unit: &'unit UnitHeader<R, Offset>, -} - -impl<'abbrev, 'unit, R, Offset> DebuggingInformationEntry<'abbrev, 'unit, R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Construct a new `DebuggingInformationEntry`. - pub fn new( - offset: UnitOffset<Offset>, - attrs_slice: R, - abbrev: &'abbrev Abbreviation, - unit: &'unit UnitHeader<R, Offset>, - ) -> Self { - DebuggingInformationEntry { - offset, - attrs_slice, - attrs_len: Cell::new(None), - abbrev, - unit, - } - } - - /// Get this entry's code. - pub fn code(&self) -> u64 { - self.abbrev.code() - } - - /// Get this entry's offset. - pub fn offset(&self) -> UnitOffset<Offset> { - self.offset - } - - /// Get this entry's `DW_TAG_whatever` tag. - /// - /// ``` - /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; - /// # let info_buf = [ - /// # // Comilation unit header - /// # - /// # // 32-bit unit length = 12 - /// # 0x0c, 0x00, 0x00, 0x00, - /// # // Version 4 - /// # 0x04, 0x00, - /// # // debug_abbrev_offset - /// # 0x00, 0x00, 0x00, 0x00, - /// # // Address size - /// # 0x04, - /// # - /// # // DIEs - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # ]; - /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); - /// # let abbrev_buf = [ - /// # // Code - /// # 0x01, - /// # // DW_TAG_subprogram - /// # 0x2e, - /// # // DW_CHILDREN_no - /// # 0x00, - /// # // Begin attributes - /// # // Attribute name = DW_AT_name - /// # 0x03, - /// # // Attribute form = DW_FORM_string - /// # 0x08, - /// # // End attributes - /// # 0x00, - /// # 0x00, - /// # // Null terminator - /// # 0x00 - /// # ]; - /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); - /// # let unit = debug_info.units().next().unwrap().unwrap(); - /// # let abbrevs = unit.abbreviations(&debug_abbrev).unwrap(); - /// # let mut cursor = unit.entries(&abbrevs); - /// # let (_, entry) = cursor.next_dfs().unwrap().unwrap(); - /// # let mut get_some_entry = || entry; - /// let entry = get_some_entry(); - /// - /// match entry.tag() { - /// gimli::DW_TAG_subprogram => - /// println!("this entry contains debug info about a function"), - /// gimli::DW_TAG_inlined_subroutine => - /// println!("this entry contains debug info about a particular instance of inlining"), - /// gimli::DW_TAG_variable => - /// println!("this entry contains debug info about a local variable"), - /// gimli::DW_TAG_formal_parameter => - /// println!("this entry contains debug info about a function parameter"), - /// otherwise => - /// println!("this entry is some other kind of data: {:?}", otherwise), - /// }; - /// ``` - pub fn tag(&self) -> constants::DwTag { - self.abbrev.tag() - } - - /// Return true if this entry's type can have children, false otherwise. - pub fn has_children(&self) -> bool { - self.abbrev.has_children() - } - - /// Iterate over this entry's set of attributes. - /// - /// ``` - /// use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; - /// - /// // Read the `.debug_info` section. - /// - /// # let info_buf = [ - /// # // Comilation unit header - /// # - /// # // 32-bit unit length = 12 - /// # 0x0c, 0x00, 0x00, 0x00, - /// # // Version 4 - /// # 0x04, 0x00, - /// # // debug_abbrev_offset - /// # 0x00, 0x00, 0x00, 0x00, - /// # // Address size - /// # 0x04, - /// # - /// # // DIEs - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # ]; - /// # let read_debug_info_section_somehow = || &info_buf; - /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); - /// - /// // Get the data about the first compilation unit out of the `.debug_info`. - /// - /// let unit = debug_info.units().next() - /// .expect("Should have at least one compilation unit") - /// .expect("and it should parse ok"); - /// - /// // Read the `.debug_abbrev` section and parse the - /// // abbreviations for our compilation unit. - /// - /// # let abbrev_buf = [ - /// # // Code - /// # 0x01, - /// # // DW_TAG_subprogram - /// # 0x2e, - /// # // DW_CHILDREN_no - /// # 0x00, - /// # // Begin attributes - /// # // Attribute name = DW_AT_name - /// # 0x03, - /// # // Attribute form = DW_FORM_string - /// # 0x08, - /// # // End attributes - /// # 0x00, - /// # 0x00, - /// # // Null terminator - /// # 0x00 - /// # ]; - /// # let read_debug_abbrev_section_somehow = || &abbrev_buf; - /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); - /// let abbrevs = unit.abbreviations(&debug_abbrev).unwrap(); - /// - /// // Get the first entry from that compilation unit. - /// - /// let mut cursor = unit.entries(&abbrevs); - /// let (_, entry) = cursor.next_dfs() - /// .expect("Should parse next entry") - /// .expect("Should have at least one entry"); - /// - /// // Finally, print the first entry's attributes. - /// - /// let mut attrs = entry.attrs(); - /// while let Some(attr) = attrs.next().unwrap() { - /// println!("Attribute name = {:?}", attr.name()); - /// println!("Attribute value = {:?}", attr.value()); - /// } - /// ``` - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn attrs<'me>(&'me self) -> AttrsIter<'abbrev, 'me, 'unit, R> { - AttrsIter { - input: self.attrs_slice.clone(), - attributes: self.abbrev.attributes(), - entry: self, - } - } - - /// Find the first attribute in this entry which has the given name, - /// and return it. Returns `Ok(None)` if no attribute is found. - pub fn attr(&self, name: constants::DwAt) -> Result<Option<Attribute<R>>> { - let mut attrs = self.attrs(); - while let Some(attr) = attrs.next()? { - if attr.name() == name { - return Ok(Some(attr)); - } - } - Ok(None) - } - - /// Find the first attribute in this entry which has the given name, - /// and return its raw value. Returns `Ok(None)` if no attribute is found. - pub fn attr_value_raw(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> { - self.attr(name) - .map(|attr| attr.map(|attr| attr.raw_value())) - } - - /// Find the first attribute in this entry which has the given name, - /// and return its normalized value. Returns `Ok(None)` if no - /// attribute is found. - pub fn attr_value(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> { - self.attr(name).map(|attr| attr.map(|attr| attr.value())) - } - - /// Return the input buffer after the last attribute. - #[inline(always)] - fn after_attrs(&self) -> Result<R> { - if let Some(attrs_len) = self.attrs_len.get() { - let mut input = self.attrs_slice.clone(); - input.skip(attrs_len)?; - Ok(input) - } else { - let mut attrs = self.attrs(); - while attrs.next()?.is_some() {} - Ok(attrs.input) - } - } - - /// Use the `DW_AT_sibling` attribute to find the input buffer for the - /// next sibling. Returns `None` if the attribute is missing or invalid. - fn sibling(&self) -> Option<R> { - let attr = self.attr_value(constants::DW_AT_sibling); - if let Ok(Some(AttributeValue::UnitRef(offset))) = attr { - if offset.0 > self.offset.0 { - if let Ok(input) = self.unit.range_from(offset..) { - return Some(input); - } - } - } - None - } - - /// Parse an entry. Returns `Ok(None)` for null entries. - #[inline(always)] - fn parse( - input: &mut R, - unit: &'unit UnitHeader<R>, - abbreviations: &'abbrev Abbreviations, - ) -> Result<Option<Self>> { - let offset = unit.header_size() + input.offset_from(&unit.entries_buf); - let code = input.read_uleb128()?; - if code == 0 { - return Ok(None); - }; - let abbrev = abbreviations.get(code).ok_or(Error::UnknownAbbreviation)?; - Ok(Some(DebuggingInformationEntry { - offset: UnitOffset(offset), - attrs_slice: input.clone(), - attrs_len: Cell::new(None), - abbrev, - unit, - })) - } -} - -/// The value of an attribute in a `DebuggingInformationEntry`. -// -// Set the discriminant size so that all variants use the same alignment -// for their data. This gives better code generation in `parse_attribute`. -#[repr(u64)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum AttributeValue<R, Offset = <R as Reader>::Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// "Refers to some location in the address space of the described program." - Addr(u64), - - /// A slice of an arbitrary number of bytes. - Block(R), - - /// A one byte constant data value. How to interpret the byte depends on context. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data1(u8), - - /// A two byte constant data value. How to interpret the bytes depends on context. - /// - /// These bytes have been converted from `R::Endian`. This may need to be reversed - /// if this was not required. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data2(u16), - - /// A four byte constant data value. How to interpret the bytes depends on context. - /// - /// These bytes have been converted from `R::Endian`. This may need to be reversed - /// if this was not required. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data4(u32), - - /// An eight byte constant data value. How to interpret the bytes depends on context. - /// - /// These bytes have been converted from `R::Endian`. This may need to be reversed - /// if this was not required. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data8(u64), - - /// A signed integer constant. - Sdata(i64), - - /// An unsigned integer constant. - Udata(u64), - - /// "The information bytes contain a DWARF expression (see Section 2.5) or - /// location description (see Section 2.6)." - Exprloc(Expression<R>), - - /// A boolean that indicates presence or absence of the attribute. - Flag(bool), - - /// An offset into another section. Which section this is an offset into - /// depends on context. - SecOffset(Offset), - - /// An offset to a set of addresses in the `.debug_addr` section. - DebugAddrBase(DebugAddrBase<Offset>), - - /// An index into a set of addresses in the `.debug_addr` section. - DebugAddrIndex(DebugAddrIndex<Offset>), - - /// An offset into the current compilation unit. - UnitRef(UnitOffset<Offset>), - - /// An offset into the current `.debug_info` section, but possibly a - /// different compilation unit from the current one. - DebugInfoRef(DebugInfoOffset<Offset>), - - /// An offset into the `.debug_info` section of the supplementary object file. - DebugInfoRefSup(DebugInfoOffset<Offset>), - - /// An offset into the `.debug_line` section. - DebugLineRef(DebugLineOffset<Offset>), - - /// An offset into either the `.debug_loc` section or the `.debug_loclists` section. - LocationListsRef(LocationListsOffset<Offset>), - - /// An offset to a set of offsets in the `.debug_loclists` section. - DebugLocListsBase(DebugLocListsBase<Offset>), - - /// An index into a set of offsets in the `.debug_loclists` section. - DebugLocListsIndex(DebugLocListsIndex<Offset>), - - /// An offset into the `.debug_macinfo` section. - DebugMacinfoRef(DebugMacinfoOffset<Offset>), - - /// An offset into the `.debug_macro` section. - DebugMacroRef(DebugMacroOffset<Offset>), - - /// An offset into the `.debug_ranges` section. - RangeListsRef(RawRangeListsOffset<Offset>), - - /// An offset to a set of offsets in the `.debug_rnglists` section. - DebugRngListsBase(DebugRngListsBase<Offset>), - - /// An index into a set of offsets in the `.debug_rnglists` section. - DebugRngListsIndex(DebugRngListsIndex<Offset>), - - /// A type signature. - DebugTypesRef(DebugTypeSignature), - - /// An offset into the `.debug_str` section. - DebugStrRef(DebugStrOffset<Offset>), - - /// An offset into the `.debug_str` section of the supplementary object file. - DebugStrRefSup(DebugStrOffset<Offset>), - - /// An offset to a set of entries in the `.debug_str_offsets` section. - DebugStrOffsetsBase(DebugStrOffsetsBase<Offset>), - - /// An index into a set of entries in the `.debug_str_offsets` section. - DebugStrOffsetsIndex(DebugStrOffsetsIndex<Offset>), - - /// An offset into the `.debug_line_str` section. - DebugLineStrRef(DebugLineStrOffset<Offset>), - - /// A slice of bytes representing a string. Does not include a final null byte. - /// Not guaranteed to be UTF-8 or anything like that. - String(R), - - /// The value of a `DW_AT_encoding` attribute. - Encoding(constants::DwAte), - - /// The value of a `DW_AT_decimal_sign` attribute. - DecimalSign(constants::DwDs), - - /// The value of a `DW_AT_endianity` attribute. - Endianity(constants::DwEnd), - - /// The value of a `DW_AT_accessibility` attribute. - Accessibility(constants::DwAccess), - - /// The value of a `DW_AT_visibility` attribute. - Visibility(constants::DwVis), - - /// The value of a `DW_AT_virtuality` attribute. - Virtuality(constants::DwVirtuality), - - /// The value of a `DW_AT_language` attribute. - Language(constants::DwLang), - - /// The value of a `DW_AT_address_class` attribute. - AddressClass(constants::DwAddr), - - /// The value of a `DW_AT_identifier_case` attribute. - IdentifierCase(constants::DwId), - - /// The value of a `DW_AT_calling_convention` attribute. - CallingConvention(constants::DwCc), - - /// The value of a `DW_AT_inline` attribute. - Inline(constants::DwInl), - - /// The value of a `DW_AT_ordering` attribute. - Ordering(constants::DwOrd), - - /// An index into the filename entries from the line number information - /// table for the compilation unit containing this value. - FileIndex(u64), - - /// An implementation-defined identifier uniquely identifying a compilation - /// unit. - DwoId(DwoId), -} - -/// An attribute in a `DebuggingInformationEntry`, consisting of a name and -/// associated value. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Attribute<R: Reader> { - name: constants::DwAt, - value: AttributeValue<R>, -} - -impl<R: Reader> Attribute<R> { - /// Get this attribute's name. - pub fn name(&self) -> constants::DwAt { - self.name - } - - /// Get this attribute's raw value. - pub fn raw_value(&self) -> AttributeValue<R> { - self.value.clone() - } - - /// Get this attribute's normalized value. - /// - /// Attribute values can potentially be encoded in multiple equivalent forms, - /// and may have special meaning depending on the attribute name. This method - /// converts the attribute value to a normalized form based on the attribute - /// name. - /// - /// See "Table 7.5: Attribute encodings" and "Table 7.6: Attribute form encodings". - pub fn value(&self) -> AttributeValue<R> { - // Table 7.5 shows the possible attribute classes for each name. - // Table 7.6 shows the possible attribute classes for each form. - // For each attribute name, we need to match on the form, and - // convert it to one of the classes that is allowed for both - // the name and the form. - // - // The individual class conversions rarely vary for each name, - // so for each class conversion we define a macro that matches - // on the allowed forms for that class. - // - // For some classes, we don't need to do any conversion, so their - // macro is empty. In the future we may want to fill them in to - // provide strict checking of the forms for each class. For now, - // they simply provide a way to document the allowed classes for - // each name. - - // DW_FORM_addr - // DW_FORM_addrx - // DW_FORM_addrx1 - // DW_FORM_addrx2 - // DW_FORM_addrx3 - // DW_FORM_addrx4 - macro_rules! address { - () => {}; - } - // DW_FORM_sec_offset - macro_rules! addrptr { - () => { - if let Some(offset) = self.offset_value() { - return AttributeValue::DebugAddrBase(DebugAddrBase(offset)); - } - }; - } - // DW_FORM_block - // DW_FORM_block1 - // DW_FORM_block2 - // DW_FORM_block4 - macro_rules! block { - () => {}; - } - // DW_FORM_sdata - // DW_FORM_udata - // DW_FORM_data1 - // DW_FORM_data2 - // DW_FORM_data4 - // DW_FORM_data8 - // DW_FORM_data16 - // DW_FORM_implicit_const - macro_rules! constant { - ($value:ident, $variant:ident) => { - if let Some(value) = self.$value() { - return AttributeValue::$variant(value); - } - }; - ($value:ident, $variant:ident, $constant:ident) => { - if let Some(value) = self.$value() { - return AttributeValue::$variant(constants::$constant(value)); - } - }; - } - // DW_FORM_exprloc - macro_rules! exprloc { - () => { - if let Some(value) = self.exprloc_value() { - return AttributeValue::Exprloc(value); - } - }; - } - // DW_FORM_flag - // DW_FORM_flag_present - macro_rules! flag { - () => {}; - } - // DW_FORM_sec_offset - macro_rules! lineptr { - () => { - if let Some(offset) = self.offset_value() { - return AttributeValue::DebugLineRef(DebugLineOffset(offset)); - } - }; - } - // This also covers `loclist` in DWARF version 5. - // DW_FORM_sec_offset - // DW_FORM_loclistx - macro_rules! loclistptr { - () => { - // DebugLocListsIndex is also an allowed form in DWARF version 5. - if let Some(offset) = self.offset_value() { - return AttributeValue::LocationListsRef(LocationListsOffset(offset)); - } - }; - } - // DW_FORM_sec_offset - macro_rules! loclistsptr { - () => { - if let Some(offset) = self.offset_value() { - return AttributeValue::DebugLocListsBase(DebugLocListsBase(offset)); - } - }; - } - // DWARF version <= 4. - // DW_FORM_sec_offset - macro_rules! macinfoptr { - () => { - if let Some(offset) = self.offset_value() { - return AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(offset)); - } - }; - } - // DWARF version >= 5. - // DW_FORM_sec_offset - macro_rules! macroptr { - () => { - if let Some(offset) = self.offset_value() { - return AttributeValue::DebugMacroRef(DebugMacroOffset(offset)); - } - }; - } - // DW_FORM_ref_addr - // DW_FORM_ref1 - // DW_FORM_ref2 - // DW_FORM_ref4 - // DW_FORM_ref8 - // DW_FORM_ref_udata - // DW_FORM_ref_sig8 - // DW_FORM_ref_sup4 - // DW_FORM_ref_sup8 - macro_rules! reference { - () => {}; - } - // This also covers `rnglist` in DWARF version 5. - // DW_FORM_sec_offset - // DW_FORM_rnglistx - macro_rules! rangelistptr { - () => { - // DebugRngListsIndex is also an allowed form in DWARF version 5. - if let Some(offset) = self.offset_value() { - return AttributeValue::RangeListsRef(RawRangeListsOffset(offset)); - } - }; - } - // DW_FORM_sec_offset - macro_rules! rnglistsptr { - () => { - if let Some(offset) = self.offset_value() { - return AttributeValue::DebugRngListsBase(DebugRngListsBase(offset)); - } - }; - } - // DW_FORM_string - // DW_FORM_strp - // DW_FORM_strx - // DW_FORM_strx1 - // DW_FORM_strx2 - // DW_FORM_strx3 - // DW_FORM_strx4 - // DW_FORM_strp_sup - // DW_FORM_line_strp - macro_rules! string { - () => {}; - } - // DW_FORM_sec_offset - macro_rules! stroffsetsptr { - () => { - if let Some(offset) = self.offset_value() { - return AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(offset)); - } - }; - } - // This isn't a separate form but it's useful to distinguish it from a generic udata. - macro_rules! dwoid { - () => { - if let Some(value) = self.udata_value() { - return AttributeValue::DwoId(DwoId(value)); - } - }; - } - - // Perform the allowed class conversions for each attribute name. - match self.name { - constants::DW_AT_sibling => { - reference!(); - } - constants::DW_AT_location => { - exprloc!(); - loclistptr!(); - } - constants::DW_AT_name => { - string!(); - } - constants::DW_AT_ordering => { - constant!(u8_value, Ordering, DwOrd); - } - constants::DW_AT_byte_size - | constants::DW_AT_bit_offset - | constants::DW_AT_bit_size => { - constant!(udata_value, Udata); - exprloc!(); - reference!(); - } - constants::DW_AT_stmt_list => { - lineptr!(); - } - constants::DW_AT_low_pc => { - address!(); - } - constants::DW_AT_high_pc => { - address!(); - constant!(udata_value, Udata); - } - constants::DW_AT_language => { - constant!(u16_value, Language, DwLang); - } - constants::DW_AT_discr => { - reference!(); - } - constants::DW_AT_discr_value => { - // constant: depends on type of DW_TAG_variant_part, - // so caller must normalize. - } - constants::DW_AT_visibility => { - constant!(u8_value, Visibility, DwVis); - } - constants::DW_AT_import => { - reference!(); - } - constants::DW_AT_string_length => { - exprloc!(); - loclistptr!(); - reference!(); - } - constants::DW_AT_common_reference => { - reference!(); - } - constants::DW_AT_comp_dir => { - string!(); - } - constants::DW_AT_const_value => { - // TODO: constant: sign depends on DW_AT_type. - block!(); - string!(); - } - constants::DW_AT_containing_type => { - reference!(); - } - constants::DW_AT_default_value => { - // TODO: constant: sign depends on DW_AT_type. - reference!(); - flag!(); - } - constants::DW_AT_inline => { - constant!(u8_value, Inline, DwInl); - } - constants::DW_AT_is_optional => { - flag!(); - } - constants::DW_AT_lower_bound => { - // TODO: constant: sign depends on DW_AT_type. - exprloc!(); - reference!(); - } - constants::DW_AT_producer => { - string!(); - } - constants::DW_AT_prototyped => { - flag!(); - } - constants::DW_AT_return_addr => { - exprloc!(); - loclistptr!(); - } - constants::DW_AT_start_scope => { - // TODO: constant - rangelistptr!(); - } - constants::DW_AT_bit_stride => { - constant!(udata_value, Udata); - exprloc!(); - reference!(); - } - constants::DW_AT_upper_bound => { - // TODO: constant: sign depends on DW_AT_type. - exprloc!(); - reference!(); - } - constants::DW_AT_abstract_origin => { - reference!(); - } - constants::DW_AT_accessibility => { - constant!(u8_value, Accessibility, DwAccess); - } - constants::DW_AT_address_class => { - constant!(udata_value, AddressClass, DwAddr); - } - constants::DW_AT_artificial => { - flag!(); - } - constants::DW_AT_base_types => { - reference!(); - } - constants::DW_AT_calling_convention => { - constant!(u8_value, CallingConvention, DwCc); - } - constants::DW_AT_count => { - // TODO: constant - exprloc!(); - reference!(); - } - constants::DW_AT_data_member_location => { - // Constants must be handled before loclistptr so that DW_FORM_data4/8 - // are correctly interpreted for DWARF version 4+. - constant!(udata_value, Udata); - exprloc!(); - loclistptr!(); - } - constants::DW_AT_decl_column => { - constant!(udata_value, Udata); - } - constants::DW_AT_decl_file => { - constant!(udata_value, FileIndex); - } - constants::DW_AT_decl_line => { - constant!(udata_value, Udata); - } - constants::DW_AT_declaration => { - flag!(); - } - constants::DW_AT_discr_list => { - block!(); - } - constants::DW_AT_encoding => { - constant!(u8_value, Encoding, DwAte); - } - constants::DW_AT_external => { - flag!(); - } - constants::DW_AT_frame_base => { - exprloc!(); - loclistptr!(); - } - constants::DW_AT_friend => { - reference!(); - } - constants::DW_AT_identifier_case => { - constant!(u8_value, IdentifierCase, DwId); - } - constants::DW_AT_macro_info => { - macinfoptr!(); - } - constants::DW_AT_namelist_item => { - reference!(); - } - constants::DW_AT_priority => { - reference!(); - } - constants::DW_AT_segment => { - exprloc!(); - loclistptr!(); - } - constants::DW_AT_specification => { - reference!(); - } - constants::DW_AT_static_link => { - exprloc!(); - loclistptr!(); - } - constants::DW_AT_type => { - reference!(); - } - constants::DW_AT_use_location => { - exprloc!(); - loclistptr!(); - } - constants::DW_AT_variable_parameter => { - flag!(); - } - constants::DW_AT_virtuality => { - constant!(u8_value, Virtuality, DwVirtuality); - } - constants::DW_AT_vtable_elem_location => { - exprloc!(); - loclistptr!(); - } - constants::DW_AT_allocated => { - // TODO: constant - exprloc!(); - reference!(); - } - constants::DW_AT_associated => { - // TODO: constant - exprloc!(); - reference!(); - } - constants::DW_AT_data_location => { - exprloc!(); - } - constants::DW_AT_byte_stride => { - constant!(udata_value, Udata); - exprloc!(); - reference!(); - } - constants::DW_AT_entry_pc => { - // TODO: constant - address!(); - } - constants::DW_AT_use_UTF8 => { - flag!(); - } - constants::DW_AT_extension => { - reference!(); - } - constants::DW_AT_ranges => { - rangelistptr!(); - } - constants::DW_AT_trampoline => { - address!(); - flag!(); - reference!(); - string!(); - } - constants::DW_AT_call_column => { - constant!(udata_value, Udata); - } - constants::DW_AT_call_file => { - constant!(udata_value, FileIndex); - } - constants::DW_AT_call_line => { - constant!(udata_value, Udata); - } - constants::DW_AT_description => { - string!(); - } - constants::DW_AT_binary_scale => { - // TODO: constant - } - constants::DW_AT_decimal_scale => { - // TODO: constant - } - constants::DW_AT_small => { - reference!(); - } - constants::DW_AT_decimal_sign => { - constant!(u8_value, DecimalSign, DwDs); - } - constants::DW_AT_digit_count => { - // TODO: constant - } - constants::DW_AT_picture_string => { - string!(); - } - constants::DW_AT_mutable => { - flag!(); - } - constants::DW_AT_threads_scaled => { - flag!(); - } - constants::DW_AT_explicit => { - flag!(); - } - constants::DW_AT_object_pointer => { - reference!(); - } - constants::DW_AT_endianity => { - constant!(u8_value, Endianity, DwEnd); - } - constants::DW_AT_elemental => { - flag!(); - } - constants::DW_AT_pure => { - flag!(); - } - constants::DW_AT_recursive => { - flag!(); - } - constants::DW_AT_signature => { - reference!(); - } - constants::DW_AT_main_subprogram => { - flag!(); - } - constants::DW_AT_data_bit_offset => { - // TODO: constant - } - constants::DW_AT_const_expr => { - flag!(); - } - constants::DW_AT_enum_class => { - flag!(); - } - constants::DW_AT_linkage_name => { - string!(); - } - constants::DW_AT_string_length_bit_size => { - // TODO: constant - } - constants::DW_AT_string_length_byte_size => { - // TODO: constant - } - constants::DW_AT_rank => { - // TODO: constant - exprloc!(); - } - constants::DW_AT_str_offsets_base => { - stroffsetsptr!(); - } - constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => { - addrptr!(); - } - constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => { - rnglistsptr!(); - } - constants::DW_AT_dwo_name => { - string!(); - } - constants::DW_AT_reference => { - flag!(); - } - constants::DW_AT_rvalue_reference => { - flag!(); - } - constants::DW_AT_macros => { - macroptr!(); - } - constants::DW_AT_call_all_calls => { - flag!(); - } - constants::DW_AT_call_all_source_calls => { - flag!(); - } - constants::DW_AT_call_all_tail_calls => { - flag!(); - } - constants::DW_AT_call_return_pc => { - address!(); - } - constants::DW_AT_call_value => { - exprloc!(); - } - constants::DW_AT_call_origin => { - exprloc!(); - } - constants::DW_AT_call_parameter => { - reference!(); - } - constants::DW_AT_call_pc => { - address!(); - } - constants::DW_AT_call_tail_call => { - flag!(); - } - constants::DW_AT_call_target => { - exprloc!(); - } - constants::DW_AT_call_target_clobbered => { - exprloc!(); - } - constants::DW_AT_call_data_location => { - exprloc!(); - } - constants::DW_AT_call_data_value => { - exprloc!(); - } - constants::DW_AT_noreturn => { - flag!(); - } - constants::DW_AT_alignment => { - // TODO: constant - } - constants::DW_AT_export_symbols => { - flag!(); - } - constants::DW_AT_deleted => { - flag!(); - } - constants::DW_AT_defaulted => { - // TODO: constant - } - constants::DW_AT_loclists_base => { - loclistsptr!(); - } - constants::DW_AT_GNU_dwo_id => { - dwoid!(); - } - _ => {} - } - self.value.clone() - } - - /// Try to convert this attribute's value to a u8. - #[inline] - pub fn u8_value(&self) -> Option<u8> { - self.value.u8_value() - } - - /// Try to convert this attribute's value to a u16. - #[inline] - pub fn u16_value(&self) -> Option<u16> { - self.value.u16_value() - } - - /// Try to convert this attribute's value to an unsigned integer. - #[inline] - pub fn udata_value(&self) -> Option<u64> { - self.value.udata_value() - } - - /// Try to convert this attribute's value to a signed integer. - #[inline] - pub fn sdata_value(&self) -> Option<i64> { - self.value.sdata_value() - } - - /// Try to convert this attribute's value to an offset. - #[inline] - pub fn offset_value(&self) -> Option<R::Offset> { - self.value.offset_value() - } - - /// Try to convert this attribute's value to an expression or location buffer. - /// - /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`. - /// The standard doesn't mention `DW_FORM_block*` as a possible form, but - /// it is encountered in practice. - #[inline] - pub fn exprloc_value(&self) -> Option<Expression<R>> { - self.value.exprloc_value() - } - - /// Try to return this attribute's value as a string slice. - /// - /// If this attribute's value is either an inline `DW_FORM_string` string, - /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` - /// section, return the attribute's string value as `Some`. Other attribute - /// value forms are returned as `None`. - /// - /// Warning: this function does not handle all possible string forms. - /// Use `Dwarf::attr_string` instead. - #[inline] - pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> { - self.value.string_value(debug_str) - } - - /// Try to return this attribute's value as a string slice. - /// - /// If this attribute's value is either an inline `DW_FORM_string` string, - /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` - /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary - /// object file, return the attribute's string value as `Some`. Other attribute - /// value forms are returned as `None`. - /// - /// Warning: this function does not handle all possible string forms. - /// Use `Dwarf::attr_string` instead. - #[inline] - pub fn string_value_sup( - &self, - debug_str: &DebugStr<R>, - debug_str_sup: Option<&DebugStr<R>>, - ) -> Option<R> { - self.value.string_value_sup(debug_str, debug_str_sup) - } -} - -impl<R, Offset> AttributeValue<R, Offset> -where - R: Reader<Offset = Offset>, - Offset: ReaderOffset, -{ - /// Try to convert this attribute's value to a u8. - pub fn u8_value(&self) -> Option<u8> { - if let Some(value) = self.udata_value() { - if value <= u64::from(u8::MAX) { - return Some(value as u8); - } - } - None - } - - /// Try to convert this attribute's value to a u16. - pub fn u16_value(&self) -> Option<u16> { - if let Some(value) = self.udata_value() { - if value <= u64::from(u16::MAX) { - return Some(value as u16); - } - } - None - } - - /// Try to convert this attribute's value to an unsigned integer. - pub fn udata_value(&self) -> Option<u64> { - Some(match *self { - AttributeValue::Data1(data) => u64::from(data), - AttributeValue::Data2(data) => u64::from(data), - AttributeValue::Data4(data) => u64::from(data), - AttributeValue::Data8(data) => data, - AttributeValue::Udata(data) => data, - AttributeValue::Sdata(data) => { - if data < 0 { - // Maybe we should emit a warning here - return None; - } - data as u64 - } - _ => return None, - }) - } - - /// Try to convert this attribute's value to a signed integer. - pub fn sdata_value(&self) -> Option<i64> { - Some(match *self { - AttributeValue::Data1(data) => i64::from(data as i8), - AttributeValue::Data2(data) => i64::from(data as i16), - AttributeValue::Data4(data) => i64::from(data as i32), - AttributeValue::Data8(data) => data as i64, - AttributeValue::Sdata(data) => data, - AttributeValue::Udata(data) => { - if data > i64::max_value() as u64 { - // Maybe we should emit a warning here - return None; - } - data as i64 - } - _ => return None, - }) - } - - /// Try to convert this attribute's value to an offset. - pub fn offset_value(&self) -> Option<R::Offset> { - // While offsets will be DW_FORM_data4/8 in DWARF version 2/3, - // these have already been converted to `SecOffset. - if let AttributeValue::SecOffset(offset) = *self { - Some(offset) - } else { - None - } - } - - /// Try to convert this attribute's value to an expression or location buffer. - /// - /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`. - /// The standard doesn't mention `DW_FORM_block*` as a possible form, but - /// it is encountered in practice. - pub fn exprloc_value(&self) -> Option<Expression<R>> { - Some(match *self { - AttributeValue::Block(ref data) => Expression(data.clone()), - AttributeValue::Exprloc(ref data) => data.clone(), - _ => return None, - }) - } - - /// Try to return this attribute's value as a string slice. - /// - /// If this attribute's value is either an inline `DW_FORM_string` string, - /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` - /// section, return the attribute's string value as `Some`. Other attribute - /// value forms are returned as `None`. - /// - /// Warning: this function does not handle all possible string forms. - /// Use `Dwarf::attr_string` instead. - pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> { - match *self { - AttributeValue::String(ref string) => Some(string.clone()), - AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(), - _ => None, - } - } - - /// Try to return this attribute's value as a string slice. - /// - /// If this attribute's value is either an inline `DW_FORM_string` string, - /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` - /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary - /// object file, return the attribute's string value as `Some`. Other attribute - /// value forms are returned as `None`. - /// - /// Warning: this function does not handle all possible string forms. - /// Use `Dwarf::attr_string` instead. - pub fn string_value_sup( - &self, - debug_str: &DebugStr<R>, - debug_str_sup: Option<&DebugStr<R>>, - ) -> Option<R> { - match *self { - AttributeValue::String(ref string) => Some(string.clone()), - AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(), - AttributeValue::DebugStrRefSup(offset) => { - debug_str_sup.and_then(|s| s.get_str(offset).ok()) - } - _ => None, - } - } -} - -fn length_u8_value<R: Reader>(input: &mut R) -> Result<R> { - let len = input.read_u8().map(R::Offset::from_u8)?; - input.split(len) -} - -fn length_u16_value<R: Reader>(input: &mut R) -> Result<R> { - let len = input.read_u16().map(R::Offset::from_u16)?; - input.split(len) -} - -fn length_u32_value<R: Reader>(input: &mut R) -> Result<R> { - let len = input.read_u32().map(R::Offset::from_u32)?; - input.split(len) -} - -fn length_uleb128_value<R: Reader>(input: &mut R) -> Result<R> { - let len = input.read_uleb128().and_then(R::Offset::from_u64)?; - input.split(len) -} - -// Return true if the given `name` can be a section offset in DWARF version 2/3. -// This is required to correctly handle relocations. -fn allow_section_offset(name: constants::DwAt, version: u16) -> bool { - match name { - constants::DW_AT_location - | constants::DW_AT_stmt_list - | constants::DW_AT_string_length - | constants::DW_AT_return_addr - | constants::DW_AT_start_scope - | constants::DW_AT_frame_base - | constants::DW_AT_macro_info - | constants::DW_AT_macros - | constants::DW_AT_segment - | constants::DW_AT_static_link - | constants::DW_AT_use_location - | constants::DW_AT_vtable_elem_location - | constants::DW_AT_ranges => true, - constants::DW_AT_data_member_location => version == 2 || version == 3, - _ => false, - } -} - -pub(crate) fn parse_attribute<R: Reader>( - input: &mut R, - encoding: Encoding, - spec: AttributeSpecification, -) -> Result<Attribute<R>> { - let mut form = spec.form(); - loop { - let value = match form { - constants::DW_FORM_indirect => { - let dynamic_form = input.read_uleb128_u16()?; - form = constants::DwForm(dynamic_form); - continue; - } - constants::DW_FORM_addr => { - let addr = input.read_address(encoding.address_size)?; - AttributeValue::Addr(addr) - } - constants::DW_FORM_block1 => { - let block = length_u8_value(input)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block2 => { - let block = length_u16_value(input)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block4 => { - let block = length_u32_value(input)?; - AttributeValue::Block(block) - } - constants::DW_FORM_block => { - let block = length_uleb128_value(input)?; - AttributeValue::Block(block) - } - constants::DW_FORM_data1 => { - let data = input.read_u8()?; - AttributeValue::Data1(data) - } - constants::DW_FORM_data2 => { - let data = input.read_u16()?; - AttributeValue::Data2(data) - } - constants::DW_FORM_data4 => { - // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets. - // Ensure we handle relocations here. - if encoding.format == Format::Dwarf32 - && allow_section_offset(spec.name(), encoding.version) - { - let offset = input.read_offset(Format::Dwarf32)?; - AttributeValue::SecOffset(offset) - } else { - let data = input.read_u32()?; - AttributeValue::Data4(data) - } - } - constants::DW_FORM_data8 => { - // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets. - // Ensure we handle relocations here. - if encoding.format == Format::Dwarf64 - && allow_section_offset(spec.name(), encoding.version) - { - let offset = input.read_offset(Format::Dwarf64)?; - AttributeValue::SecOffset(offset) - } else { - let data = input.read_u64()?; - AttributeValue::Data8(data) - } - } - constants::DW_FORM_data16 => { - let block = input.split(R::Offset::from_u8(16))?; - AttributeValue::Block(block) - } - constants::DW_FORM_udata => { - let data = input.read_uleb128()?; - AttributeValue::Udata(data) - } - constants::DW_FORM_sdata => { - let data = input.read_sleb128()?; - AttributeValue::Sdata(data) - } - constants::DW_FORM_exprloc => { - let block = length_uleb128_value(input)?; - AttributeValue::Exprloc(Expression(block)) - } - constants::DW_FORM_flag => { - let present = input.read_u8()?; - AttributeValue::Flag(present != 0) - } - constants::DW_FORM_flag_present => { - // FlagPresent is this weird compile time always true thing that - // isn't actually present in the serialized DIEs, only in the abbreviation. - AttributeValue::Flag(true) - } - constants::DW_FORM_sec_offset => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::SecOffset(offset) - } - constants::DW_FORM_ref1 => { - let reference = input.read_u8().map(R::Offset::from_u8)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref2 => { - let reference = input.read_u16().map(R::Offset::from_u16)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref4 => { - let reference = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref8 => { - let reference = input.read_u64().and_then(R::Offset::from_u64)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref_udata => { - let reference = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::UnitRef(UnitOffset(reference)) - } - constants::DW_FORM_ref_addr => { - // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr - // has the same size as an address on the target system. This was changed - // in DWARF version 3. - let offset = if encoding.version == 2 { - input.read_sized_offset(encoding.address_size)? - } else { - input.read_offset(encoding.format)? - }; - AttributeValue::DebugInfoRef(DebugInfoOffset(offset)) - } - constants::DW_FORM_ref_sig8 => { - let signature = input.read_u64()?; - AttributeValue::DebugTypesRef(DebugTypeSignature(signature)) - } - constants::DW_FORM_ref_sup4 => { - let offset = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) - } - constants::DW_FORM_ref_sup8 => { - let offset = input.read_u64().and_then(R::Offset::from_u64)?; - AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) - } - constants::DW_FORM_GNU_ref_alt => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) - } - constants::DW_FORM_string => { - let string = input.read_null_terminated_slice()?; - AttributeValue::String(string) - } - constants::DW_FORM_strp => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugStrRef(DebugStrOffset(offset)) - } - constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugStrRefSup(DebugStrOffset(offset)) - } - constants::DW_FORM_line_strp => { - let offset = input.read_offset(encoding.format)?; - AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset)) - } - constants::DW_FORM_implicit_const => { - let data = spec - .implicit_const_value() - .ok_or(Error::InvalidImplicitConst)?; - AttributeValue::Sdata(data) - } - constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx1 => { - let index = input.read_u8().map(R::Offset::from_u8)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx2 => { - let index = input.read_u16().map(R::Offset::from_u16)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx3 => { - let index = input.read_uint(3).and_then(R::Offset::from_u64)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_strx4 => { - let index = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) - } - constants::DW_FORM_addrx | constants::DW_FORM_GNU_addr_index => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_addrx1 => { - let index = input.read_u8().map(R::Offset::from_u8)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_addrx2 => { - let index = input.read_u16().map(R::Offset::from_u16)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_addrx3 => { - let index = input.read_uint(3).and_then(R::Offset::from_u64)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_addrx4 => { - let index = input.read_u32().map(R::Offset::from_u32)?; - AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) - } - constants::DW_FORM_loclistx => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugLocListsIndex(DebugLocListsIndex(index)) - } - constants::DW_FORM_rnglistx => { - let index = input.read_uleb128().and_then(R::Offset::from_u64)?; - AttributeValue::DebugRngListsIndex(DebugRngListsIndex(index)) - } - _ => { - return Err(Error::UnknownForm); - } - }; - let attr = Attribute { - name: spec.name(), - value, - }; - return Ok(attr); - } -} - -pub(crate) fn skip_attributes<R: Reader>( - input: &mut R, - encoding: Encoding, - specs: &[AttributeSpecification], -) -> Result<()> { - let mut skip_bytes = R::Offset::from_u8(0); - for spec in specs { - let mut form = spec.form(); - loop { - if let Some(len) = get_attribute_size(form, encoding) { - // We know the length of this attribute. Accumulate that length. - skip_bytes += R::Offset::from_u8(len); - break; - } - - // We have encountered a variable-length attribute. - if skip_bytes != R::Offset::from_u8(0) { - // Skip the accumulated skip bytes and then read the attribute normally. - input.skip(skip_bytes)?; - skip_bytes = R::Offset::from_u8(0); - } - - match form { - constants::DW_FORM_indirect => { - let dynamic_form = input.read_uleb128_u16()?; - form = constants::DwForm(dynamic_form); - continue; - } - constants::DW_FORM_block1 => { - skip_bytes = input.read_u8().map(R::Offset::from_u8)?; - } - constants::DW_FORM_block2 => { - skip_bytes = input.read_u16().map(R::Offset::from_u16)?; - } - constants::DW_FORM_block4 => { - skip_bytes = input.read_u32().map(R::Offset::from_u32)?; - } - constants::DW_FORM_block | constants::DW_FORM_exprloc => { - skip_bytes = input.read_uleb128().and_then(R::Offset::from_u64)?; - } - constants::DW_FORM_string => { - let _ = input.read_null_terminated_slice()?; - } - constants::DW_FORM_udata - | constants::DW_FORM_sdata - | constants::DW_FORM_ref_udata - | constants::DW_FORM_strx - | constants::DW_FORM_GNU_str_index - | constants::DW_FORM_addrx - | constants::DW_FORM_GNU_addr_index - | constants::DW_FORM_loclistx - | constants::DW_FORM_rnglistx => { - input.skip_leb128()?; - } - _ => { - return Err(Error::UnknownForm); - } - }; - break; - } - } - if skip_bytes != R::Offset::from_u8(0) { - // Skip the remaining accumulated skip bytes. - input.skip(skip_bytes)?; - } - Ok(()) -} - -/// An iterator over a particular entry's attributes. -/// -/// See [the documentation for -/// `DebuggingInformationEntry::attrs()`](./struct.DebuggingInformationEntry.html#method.attrs) -/// for details. -/// -/// Can be [used with -/// `FallibleIterator`](./index.html#using-with-fallibleiterator). -#[derive(Clone, Copy, Debug)] -pub struct AttrsIter<'abbrev, 'entry, 'unit, R: Reader> { - input: R, - attributes: &'abbrev [AttributeSpecification], - entry: &'entry DebuggingInformationEntry<'abbrev, 'unit, R>, -} - -impl<'abbrev, 'entry, 'unit, R: Reader> AttrsIter<'abbrev, 'entry, 'unit, R> { - /// Advance the iterator and return the next attribute. - /// - /// Returns `None` when iteration is finished. If an error - /// occurs while parsing the next attribute, then this error - /// is returned, and all subsequent calls return `None`. - #[inline(always)] - pub fn next(&mut self) -> Result<Option<Attribute<R>>> { - if self.attributes.is_empty() { - // Now that we have parsed all of the attributes, we know where - // either (1) this entry's children start, if the abbreviation says - // this entry has children; or (2) where this entry's siblings - // begin. - if let Some(end) = self.entry.attrs_len.get() { - debug_assert_eq!(end, self.input.offset_from(&self.entry.attrs_slice)); - } else { - self.entry - .attrs_len - .set(Some(self.input.offset_from(&self.entry.attrs_slice))); - } - - return Ok(None); - } - - let spec = self.attributes[0]; - let rest_spec = &self.attributes[1..]; - match parse_attribute(&mut self.input, self.entry.unit.encoding(), spec) { - Ok(attr) => { - self.attributes = rest_spec; - Ok(Some(attr)) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<'abbrev, 'entry, 'unit, R: Reader> fallible_iterator::FallibleIterator - for AttrsIter<'abbrev, 'entry, 'unit, R> -{ - type Item = Attribute<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - AttrsIter::next(self) - } -} - -/// A raw reader of the data that defines the Debugging Information Entries. -/// -/// `EntriesRaw` provides primitives to read the components of Debugging Information -/// Entries (DIEs). A DIE consists of an abbreviation code (read with `read_abbreviation`) -/// followed by a number of attributes (read with `read_attribute`). -/// The user must provide the control flow to read these correctly. -/// In particular, all attributes must always be read before reading another -/// abbreviation code. -/// -/// `EntriesRaw` lacks some features of `EntriesCursor`, such as the ability to skip -/// to the next sibling DIE. However, this also allows it to optimize better, since it -/// does not need to perform the extra bookkeeping required to support these features, -/// and thus it is suitable for cases where performance is important. -/// -/// ## Example Usage -/// ```rust,no_run -/// # fn example() -> Result<(), gimli::Error> { -/// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian); -/// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); -/// let unit = get_some_unit(); -/// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian); -/// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); -/// let abbrevs = get_abbrevs_for_unit(&unit); -/// -/// let mut entries = unit.entries_raw(&abbrevs, None)?; -/// while !entries.is_empty() { -/// let abbrev = if let Some(abbrev) = entries.read_abbreviation()? { -/// abbrev -/// } else { -/// // Null entry with no attributes. -/// continue -/// }; -/// match abbrev.tag() { -/// gimli::DW_TAG_subprogram => { -/// // Loop over attributes for DIEs we care about. -/// for spec in abbrev.attributes() { -/// let attr = entries.read_attribute(*spec)?; -/// match attr.name() { -/// // Handle attributes. -/// _ => {} -/// } -/// } -/// } -/// _ => { -/// // Skip attributes for DIEs we don't care about. -/// entries.skip_attributes(abbrev.attributes()); -/// } -/// } -/// } -/// # unreachable!() -/// # } -/// ``` -#[derive(Clone, Debug)] -pub struct EntriesRaw<'abbrev, 'unit, R> -where - R: Reader, -{ - input: R, - unit: &'unit UnitHeader<R>, - abbreviations: &'abbrev Abbreviations, - depth: isize, -} - -impl<'abbrev, 'unit, R: Reader> EntriesRaw<'abbrev, 'unit, R> { - /// Return true if there is no more input. - #[inline] - pub fn is_empty(&self) -> bool { - self.input.is_empty() - } - - /// Return the unit offset at which the reader will read next. - /// - /// If you want the offset of the next entry, then this must be called prior to reading - /// the next entry. - pub fn next_offset(&self) -> UnitOffset<R::Offset> { - UnitOffset(self.unit.header_size() + self.input.offset_from(&self.unit.entries_buf)) - } - - /// Return the depth of the next entry. - /// - /// This depth is updated when `read_abbreviation` is called, and is updated - /// based on null entries and the `has_children` field in the abbreviation. - #[inline] - pub fn next_depth(&self) -> isize { - self.depth - } - - /// Read an abbreviation code and lookup the corresponding `Abbreviation`. - /// - /// Returns `Ok(None)` for null entries. - #[inline] - pub fn read_abbreviation(&mut self) -> Result<Option<&'abbrev Abbreviation>> { - let code = self.input.read_uleb128()?; - if code == 0 { - self.depth -= 1; - return Ok(None); - }; - let abbrev = self - .abbreviations - .get(code) - .ok_or(Error::UnknownAbbreviation)?; - if abbrev.has_children() { - self.depth += 1; - } - Ok(Some(abbrev)) - } - - /// Read an attribute. - #[inline] - pub fn read_attribute(&mut self, spec: AttributeSpecification) -> Result<Attribute<R>> { - parse_attribute(&mut self.input, self.unit.encoding(), spec) - } - - /// Skip all the attributes of an abbreviation. - #[inline] - pub fn skip_attributes(&mut self, specs: &[AttributeSpecification]) -> Result<()> { - skip_attributes(&mut self.input, self.unit.encoding(), specs) - } -} - -/// A cursor into the Debugging Information Entries tree for a compilation unit. -/// -/// The `EntriesCursor` can traverse the DIE tree in DFS order using `next_dfs()`, -/// or skip to the next sibling of the entry the cursor is currently pointing to -/// using `next_sibling()`. -/// -/// It is also possible to traverse the DIE tree at a lower abstraction level -/// using `next_entry()`. This method does not skip over null entries, or provide -/// any indication of the current tree depth. In this case, you must use `current()` -/// to obtain the current entry, and `current().has_children()` to determine if -/// the entry following the current entry will be a sibling or child. `current()` -/// will return `None` if the current entry is a null entry, which signifies the -/// end of the current tree depth. -#[derive(Clone, Debug)] -pub struct EntriesCursor<'abbrev, 'unit, R> -where - R: Reader, -{ - input: R, - unit: &'unit UnitHeader<R>, - abbreviations: &'abbrev Abbreviations, - cached_current: Option<DebuggingInformationEntry<'abbrev, 'unit, R>>, - delta_depth: isize, -} - -impl<'abbrev, 'unit, R: Reader> EntriesCursor<'abbrev, 'unit, R> { - /// Get a reference to the entry that the cursor is currently pointing to. - /// - /// If the cursor is not pointing at an entry, or if the current entry is a - /// null entry, then `None` is returned. - #[inline] - pub fn current(&self) -> Option<&DebuggingInformationEntry<'abbrev, 'unit, R>> { - self.cached_current.as_ref() - } - - /// Move the cursor to the next DIE in the tree. - /// - /// Returns `Some` if there is a next entry, even if this entry is null. - /// If there is no next entry, then `None` is returned. - pub fn next_entry(&mut self) -> Result<Option<()>> { - if let Some(ref current) = self.cached_current { - self.input = current.after_attrs()?; - } - - if self.input.is_empty() { - self.cached_current = None; - self.delta_depth = 0; - return Ok(None); - } - - match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) { - Ok(Some(entry)) => { - self.delta_depth = entry.has_children() as isize; - self.cached_current = Some(entry); - Ok(Some(())) - } - Ok(None) => { - self.delta_depth = -1; - self.cached_current = None; - Ok(Some(())) - } - Err(e) => { - self.input.empty(); - self.delta_depth = 0; - self.cached_current = None; - Err(e) - } - } - } - - /// Move the cursor to the next DIE in the tree in DFS order. - /// - /// Upon successful movement of the cursor, return the delta traversal - /// depth and the entry: - /// - /// * If we moved down into the previous current entry's children, we get - /// `Some((1, entry))`. - /// - /// * If we moved to the previous current entry's sibling, we get - /// `Some((0, entry))`. - /// - /// * If the previous entry does not have any siblings and we move up to - /// its parent's next sibling, then we get `Some((-1, entry))`. Note that - /// if the parent doesn't have a next sibling, then it could go up to the - /// parent's parent's next sibling and return `Some((-2, entry))`, etc. - /// - /// If there is no next entry, then `None` is returned. - /// - /// Here is an example that finds the first entry in a compilation unit that - /// does not have any children. - /// - /// ``` - /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; - /// # let info_buf = [ - /// # // Comilation unit header - /// # - /// # // 32-bit unit length = 25 - /// # 0x19, 0x00, 0x00, 0x00, - /// # // Version 4 - /// # 0x04, 0x00, - /// # // debug_abbrev_offset - /// # 0x00, 0x00, 0x00, 0x00, - /// # // Address size - /// # 0x04, - /// # - /// # // DIEs - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # ]; - /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); - /// # - /// # let abbrev_buf = [ - /// # // Code - /// # 0x01, - /// # // DW_TAG_subprogram - /// # 0x2e, - /// # // DW_CHILDREN_yes - /// # 0x01, - /// # // Begin attributes - /// # // Attribute name = DW_AT_name - /// # 0x03, - /// # // Attribute form = DW_FORM_string - /// # 0x08, - /// # // End attributes - /// # 0x00, - /// # 0x00, - /// # // Null terminator - /// # 0x00 - /// # ]; - /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); - /// # - /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); - /// - /// let unit = get_some_unit(); - /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); - /// let abbrevs = get_abbrevs_for_unit(&unit); - /// - /// let mut first_entry_with_no_children = None; - /// let mut cursor = unit.entries(&abbrevs); - /// - /// // Move the cursor to the root. - /// assert!(cursor.next_dfs().unwrap().is_some()); - /// - /// // Traverse the DIE tree in depth-first search order. - /// let mut depth = 0; - /// while let Some((delta_depth, current)) = cursor.next_dfs().expect("Should parse next dfs") { - /// // Update depth value, and break out of the loop when we - /// // return to the original starting position. - /// depth += delta_depth; - /// if depth <= 0 { - /// break; - /// } - /// - /// first_entry_with_no_children = Some(current.clone()); - /// } - /// - /// println!("The first entry with no children is {:?}", - /// first_entry_with_no_children.unwrap()); - /// ``` - pub fn next_dfs( - &mut self, - ) -> Result<Option<(isize, &DebuggingInformationEntry<'abbrev, 'unit, R>)>> { - let mut delta_depth = self.delta_depth; - loop { - // The next entry should be the one we want. - if self.next_entry()?.is_some() { - if let Some(ref entry) = self.cached_current { - return Ok(Some((delta_depth, entry))); - } - - // next_entry() read a null entry. - delta_depth += self.delta_depth; - } else { - return Ok(None); - } - } - } - - /// Move the cursor to the next sibling DIE of the current one. - /// - /// Returns `Ok(Some(entry))` when the cursor has been moved to - /// the next sibling, `Ok(None)` when there is no next sibling. - /// - /// The depth of the cursor is never changed if this method returns `Ok`. - /// Once `Ok(None)` is returned, this method will continue to return - /// `Ok(None)` until either `next_entry` or `next_dfs` is called. - /// - /// Here is an example that iterates over all of the direct children of the - /// root entry: - /// - /// ``` - /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; - /// # let info_buf = [ - /// # // Comilation unit header - /// # - /// # // 32-bit unit length = 25 - /// # 0x19, 0x00, 0x00, 0x00, - /// # // Version 4 - /// # 0x04, 0x00, - /// # // debug_abbrev_offset - /// # 0x00, 0x00, 0x00, 0x00, - /// # // Address size - /// # 0x04, - /// # - /// # // DIEs - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // Abbreviation code - /// # 0x01, - /// # // Attribute of form DW_FORM_string = "foo\0" - /// # 0x66, 0x6f, 0x6f, 0x00, - /// # - /// # // Children - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # - /// # // End of children - /// # 0x00, - /// # ]; - /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); - /// # - /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); - /// - /// # let abbrev_buf = [ - /// # // Code - /// # 0x01, - /// # // DW_TAG_subprogram - /// # 0x2e, - /// # // DW_CHILDREN_yes - /// # 0x01, - /// # // Begin attributes - /// # // Attribute name = DW_AT_name - /// # 0x03, - /// # // Attribute form = DW_FORM_string - /// # 0x08, - /// # // End attributes - /// # 0x00, - /// # 0x00, - /// # // Null terminator - /// # 0x00 - /// # ]; - /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); - /// # - /// let unit = get_some_unit(); - /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); - /// let abbrevs = get_abbrevs_for_unit(&unit); - /// - /// let mut cursor = unit.entries(&abbrevs); - /// - /// // Move the cursor to the root. - /// assert!(cursor.next_dfs().unwrap().is_some()); - /// - /// // Move the cursor to the root's first child. - /// assert!(cursor.next_dfs().unwrap().is_some()); - /// - /// // Iterate the root's children. - /// loop { - /// { - /// let current = cursor.current().expect("Should be at an entry"); - /// println!("{:?} is a child of the root", current); - /// } - /// - /// if cursor.next_sibling().expect("Should parse next sibling").is_none() { - /// break; - /// } - /// } - /// ``` - pub fn next_sibling( - &mut self, - ) -> Result<Option<&DebuggingInformationEntry<'abbrev, 'unit, R>>> { - if self.current().is_none() { - // We're already at the null for the end of the sibling list. - return Ok(None); - } - - // Loop until we find an entry at the current level. - let mut depth = 0; - loop { - // Use is_some() and unwrap() to keep borrow checker happy. - if self.current().is_some() && self.current().unwrap().has_children() { - if let Some(sibling_input) = self.current().unwrap().sibling() { - // Fast path: this entry has a DW_AT_sibling - // attribute pointing to its sibling, so jump - // to it (which keeps us at the same depth). - self.input = sibling_input; - self.cached_current = None; - } else { - // This entry has children, so the next entry is - // down one level. - depth += 1; - } - } - - if self.next_entry()?.is_none() { - // End of input. - return Ok(None); - } - - if depth == 0 { - // Found an entry at the current level. - return Ok(self.current()); - } - - if self.current().is_none() { - // A null entry means the end of a child list, so we're - // back up a level. - depth -= 1; - } - } - } -} - -/// The state information for a tree view of the Debugging Information Entries. -/// -/// The `EntriesTree` can be used to recursively iterate through the DIE -/// tree, following the parent/child relationships. The `EntriesTree` contains -/// shared state for all nodes in the tree, avoiding any duplicate parsing of -/// entries during the traversal. -/// -/// ## Example Usage -/// ```rust,no_run -/// # fn example() -> Result<(), gimli::Error> { -/// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian); -/// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); -/// let unit = get_some_unit(); -/// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian); -/// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); -/// let abbrevs = get_abbrevs_for_unit(&unit); -/// -/// let mut tree = unit.entries_tree(&abbrevs, None)?; -/// let root = tree.root()?; -/// process_tree(root)?; -/// # unreachable!() -/// # } -/// -/// fn process_tree<R>(mut node: gimli::EntriesTreeNode<R>) -> gimli::Result<()> -/// where R: gimli::Reader -/// { -/// { -/// // Examine the entry attributes. -/// let mut attrs = node.entry().attrs(); -/// while let Some(attr) = attrs.next()? { -/// } -/// } -/// let mut children = node.children(); -/// while let Some(child) = children.next()? { -/// // Recursively process a child. -/// process_tree(child); -/// } -/// Ok(()) -/// } -/// ``` -#[derive(Clone, Debug)] -pub struct EntriesTree<'abbrev, 'unit, R> -where - R: Reader, -{ - root: R, - unit: &'unit UnitHeader<R>, - abbreviations: &'abbrev Abbreviations, - input: R, - entry: Option<DebuggingInformationEntry<'abbrev, 'unit, R>>, - depth: isize, -} - -impl<'abbrev, 'unit, R: Reader> EntriesTree<'abbrev, 'unit, R> { - fn new(root: R, unit: &'unit UnitHeader<R>, abbreviations: &'abbrev Abbreviations) -> Self { - let input = root.clone(); - EntriesTree { - root, - unit, - abbreviations, - input, - entry: None, - depth: 0, - } - } - - /// Returns the root node of the tree. - pub fn root<'me>(&'me mut self) -> Result<EntriesTreeNode<'abbrev, 'unit, 'me, R>> { - self.input = self.root.clone(); - self.entry = - DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations)?; - if self.entry.is_none() { - return Err(Error::UnexpectedNull); - } - self.depth = 0; - Ok(EntriesTreeNode::new(self, 1)) - } - - /// Move the cursor to the next entry at the specified depth. - /// - /// Requires `depth <= self.depth + 1`. - /// - /// Returns `true` if successful. - fn next(&mut self, depth: isize) -> Result<bool> { - if self.depth < depth { - debug_assert_eq!(self.depth + 1, depth); - - match self.entry { - Some(ref entry) => { - if !entry.has_children() { - return Ok(false); - } - self.depth += 1; - self.input = entry.after_attrs()?; - } - None => return Ok(false), - } - - if self.input.is_empty() { - self.entry = None; - return Ok(false); - } - - return match DebuggingInformationEntry::parse( - &mut self.input, - self.unit, - self.abbreviations, - ) { - Ok(entry) => { - self.entry = entry; - Ok(self.entry.is_some()) - } - Err(e) => { - self.input.empty(); - self.entry = None; - Err(e) - } - }; - } - - loop { - match self.entry { - Some(ref entry) => { - if entry.has_children() { - if let Some(sibling_input) = entry.sibling() { - // Fast path: this entry has a DW_AT_sibling - // attribute pointing to its sibling, so jump - // to it (which keeps us at the same depth). - self.input = sibling_input; - } else { - // This entry has children, so the next entry is - // down one level. - self.depth += 1; - self.input = entry.after_attrs()?; - } - } else { - // This entry has no children, so next entry is at same depth. - self.input = entry.after_attrs()?; - } - } - None => { - // This entry is a null, so next entry is up one level. - self.depth -= 1; - } - } - - if self.input.is_empty() { - self.entry = None; - return Ok(false); - } - - match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) { - Ok(entry) => { - self.entry = entry; - if self.depth == depth { - return Ok(self.entry.is_some()); - } - } - Err(e) => { - self.input.empty(); - self.entry = None; - return Err(e); - } - } - } - } -} - -/// A node in the Debugging Information Entry tree. -/// -/// The root node of a tree can be obtained -/// via [`EntriesTree::root`](./struct.EntriesTree.html#method.root). -#[derive(Debug)] -pub struct EntriesTreeNode<'abbrev, 'unit, 'tree, R: Reader> { - tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, - depth: isize, -} - -impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeNode<'abbrev, 'unit, 'tree, R> { - fn new( - tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, - depth: isize, - ) -> EntriesTreeNode<'abbrev, 'unit, 'tree, R> { - debug_assert!(tree.entry.is_some()); - EntriesTreeNode { tree, depth } - } - - /// Returns the current entry in the tree. - pub fn entry(&self) -> &DebuggingInformationEntry<'abbrev, 'unit, R> { - // We never create a node without an entry. - self.tree.entry.as_ref().unwrap() - } - - /// Create an iterator for the children of the current entry. - /// - /// The current entry can no longer be accessed after creating the - /// iterator. - pub fn children(self) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { - EntriesTreeIter::new(self.tree, self.depth) - } -} - -/// An iterator that allows traversal of the children of an -/// `EntriesTreeNode`. -/// -/// The items returned by this iterator are also `EntriesTreeNode`s, -/// which allow recursive traversal of grandchildren, etc. -#[derive(Debug)] -pub struct EntriesTreeIter<'abbrev, 'unit, 'tree, R: Reader> { - tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, - depth: isize, - empty: bool, -} - -impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { - fn new( - tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, - depth: isize, - ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { - EntriesTreeIter { - tree, - depth, - empty: false, - } - } - - /// Returns an `EntriesTreeNode` for the next child entry. - /// - /// Returns `None` if there are no more children. - pub fn next<'me>(&'me mut self) -> Result<Option<EntriesTreeNode<'abbrev, 'unit, 'me, R>>> { - if self.empty { - Ok(None) - } else if self.tree.next(self.depth)? { - Ok(Some(EntriesTreeNode::new(self.tree, self.depth + 1))) - } else { - self.empty = true; - Ok(None) - } - } -} - -/// Parse a type unit header's unique type signature. Callers should handle -/// unique-ness checking. -fn parse_type_signature<R: Reader>(input: &mut R) -> Result<DebugTypeSignature> { - input.read_u64().map(DebugTypeSignature) -} - -/// Parse a type unit header's type offset. -fn parse_type_offset<R: Reader>(input: &mut R, format: Format) -> Result<UnitOffset<R::Offset>> { - input.read_offset(format).map(UnitOffset) -} - -/// The `DebugTypes` struct represents the DWARF type information -/// found in the `.debug_types` section. -#[derive(Debug, Default, Clone, Copy)] -pub struct DebugTypes<R> { - debug_types_section: R, -} - -impl<'input, Endian> DebugTypes<EndianSlice<'input, Endian>> -where - Endian: Endianity, -{ - /// Construct a new `DebugTypes` instance from the data in the `.debug_types` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_types` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on macOS, etc. - /// - /// ``` - /// use gimli::{DebugTypes, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # let read_debug_types_section_somehow = || &buf; - /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian); - /// ``` - pub fn new(debug_types_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_types_section, endian)) - } -} - -impl<T> DebugTypes<T> { - /// Create a `DebugTypes` section that references the data in `self`. - /// - /// This is useful when `R` implements `Reader` but `T` does not. - /// - /// ## Example Usage - /// - /// ```rust,no_run - /// # let load_section = || unimplemented!(); - /// // Read the DWARF section into a `Vec` with whatever object loader you're using. - /// let owned_section: gimli::DebugTypes<Vec<u8>> = load_section(); - /// // Create a reference to the DWARF section. - /// let section = owned_section.borrow(|section| { - /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) - /// }); - /// ``` - pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugTypes<R> - where - F: FnMut(&'a T) -> R, - { - borrow(&self.debug_types_section).into() - } -} - -impl<R> Section<R> for DebugTypes<R> { - fn id() -> SectionId { - SectionId::DebugTypes - } - - fn reader(&self) -> &R { - &self.debug_types_section - } -} - -impl<R> From<R> for DebugTypes<R> { - fn from(debug_types_section: R) -> Self { - DebugTypes { - debug_types_section, - } - } -} - -impl<R: Reader> DebugTypes<R> { - /// Iterate the type-units in this `.debug_types` section. - /// - /// ``` - /// use gimli::{DebugTypes, LittleEndian}; - /// - /// # let buf = []; - /// # let read_debug_types_section_somehow = || &buf; - /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian); - /// - /// let mut iter = debug_types.units(); - /// while let Some(unit) = iter.next().unwrap() { - /// println!("unit's length is {}", unit.unit_length()); - /// } - /// ``` - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn units(&self) -> DebugTypesUnitHeadersIter<R> { - DebugTypesUnitHeadersIter { - input: self.debug_types_section.clone(), - offset: DebugTypesOffset(R::Offset::from_u8(0)), - } - } -} - -/// An iterator over the type-units of this `.debug_types` section. -/// -/// See the [documentation on -/// `DebugTypes::units`](./struct.DebugTypes.html#method.units) for -/// more detail. -#[derive(Clone, Debug)] -pub struct DebugTypesUnitHeadersIter<R: Reader> { - input: R, - offset: DebugTypesOffset<R::Offset>, -} - -impl<R: Reader> DebugTypesUnitHeadersIter<R> { - /// Advance the iterator to the next type unit header. - pub fn next(&mut self) -> Result<Option<UnitHeader<R>>> { - if self.input.is_empty() { - Ok(None) - } else { - let len = self.input.len(); - match parse_unit_header(&mut self.input, self.offset.into()) { - Ok(header) => { - self.offset.0 += len - self.input.len(); - Ok(Some(header)) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } - } -} - -#[cfg(feature = "fallible-iterator")] -impl<R: Reader> fallible_iterator::FallibleIterator for DebugTypesUnitHeadersIter<R> { - type Item = UnitHeader<R>; - type Error = Error; - - fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> { - DebugTypesUnitHeadersIter::next(self) - } -} - -#[cfg(test)] -// Tests require leb128::write. -#[cfg(feature = "write")] -mod tests { - use super::*; - use crate::constants; - use crate::constants::*; - use crate::endianity::{Endianity, LittleEndian}; - use crate::leb128; - use crate::read::abbrev::tests::AbbrevSectionMethods; - use crate::read::{ - Abbreviation, AttributeSpecification, DebugAbbrev, EndianSlice, Error, Result, - }; - use crate::test_util::GimliSectionMethods; - use alloc::vec::Vec; - use core::cell::Cell; - use test_assembler::{Endian, Label, LabelMaker, Section}; - - // Mixin methods for `Section` to help define binary test data. - - trait UnitSectionMethods { - fn unit<'input, E>(self, unit: &mut UnitHeader<EndianSlice<'input, E>>) -> Self - where - E: Endianity; - fn die<F>(self, code: u64, attr: F) -> Self - where - F: Fn(Section) -> Section; - fn die_null(self) -> Self; - fn attr_string(self, s: &str) -> Self; - fn attr_ref1(self, o: u8) -> Self; - fn offset(self, offset: usize, format: Format) -> Self; - } - - impl UnitSectionMethods for Section { - fn unit<'input, E>(self, unit: &mut UnitHeader<EndianSlice<'input, E>>) -> Self - where - E: Endianity, - { - let size = self.size(); - let length = Label::new(); - let start = Label::new(); - let end = Label::new(); - - let section = match unit.format() { - Format::Dwarf32 => self.L32(&length), - Format::Dwarf64 => self.L32(0xffff_ffff).L64(&length), - }; - - let section = match unit.version() { - 2 | 3 | 4 => section - .mark(&start) - .L16(unit.version()) - .offset(unit.debug_abbrev_offset.0, unit.format()) - .D8(unit.address_size()), - 5 => section - .mark(&start) - .L16(unit.version()) - .D8(unit.type_().dw_ut().0) - .D8(unit.address_size()) - .offset(unit.debug_abbrev_offset.0, unit.format()), - _ => unreachable!(), - }; - - let section = match unit.type_() { - UnitType::Compilation | UnitType::Partial => { - unit.unit_offset = DebugInfoOffset(size as usize).into(); - section - } - UnitType::Type { - type_signature, - type_offset, - } - | UnitType::SplitType { - type_signature, - type_offset, - } => { - if unit.version() == 5 { - unit.unit_offset = DebugInfoOffset(size as usize).into(); - } else { - unit.unit_offset = DebugTypesOffset(size as usize).into(); - } - section - .L64(type_signature.0) - .offset(type_offset.0, unit.format()) - } - UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => { - unit.unit_offset = DebugInfoOffset(size as usize).into(); - section.L64(dwo_id.0) - } - }; - - let section = section.append_bytes(unit.entries_buf.slice()).mark(&end); - - unit.unit_length = (&end - &start) as usize; - length.set_const(unit.unit_length as u64); - - section - } - - fn die<F>(self, code: u64, attr: F) -> Self - where - F: Fn(Section) -> Section, - { - let section = self.uleb(code); - attr(section) - } - - fn die_null(self) -> Self { - self.D8(0) - } - - fn attr_string(self, attr: &str) -> Self { - self.append_bytes(attr.as_bytes()).D8(0) - } - - fn attr_ref1(self, attr: u8) -> Self { - self.D8(attr) - } - - fn offset(self, offset: usize, format: Format) -> Self { - match format { - Format::Dwarf32 => self.L32(offset as u32), - Format::Dwarf64 => self.L64(offset as u64), - } - } - } - - /// Ensure that `UnitHeader<R>` is covariant wrt R. - #[test] - fn test_unit_header_variance() { - /// This only needs to compile. - fn _f<'a: 'b, 'b, E: Endianity>( - x: UnitHeader<EndianSlice<'a, E>>, - ) -> UnitHeader<EndianSlice<'b, E>> { - x - } - } - - #[test] - fn test_parse_debug_abbrev_offset_32() { - let section = Section::with_endian(Endian::Little).L32(0x0403_0201); - let buf = section.get_contents().unwrap(); - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_abbrev_offset(buf, Format::Dwarf32) { - Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0403_0201)), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_abbrev_offset_32_incomplete() { - let buf = [0x01, 0x02]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_abbrev_offset(buf, Format::Dwarf32) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_debug_abbrev_offset_64() { - let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201); - let buf = section.get_contents().unwrap(); - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_abbrev_offset(buf, Format::Dwarf64) { - Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0807_0605_0403_0201)), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_abbrev_offset_64_incomplete() { - let buf = [0x01, 0x02]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_abbrev_offset(buf, Format::Dwarf64) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_info_offset_32() { - let section = Section::with_endian(Endian::Little).L32(0x0403_0201); - let buf = section.get_contents().unwrap(); - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_info_offset(buf, Format::Dwarf32) { - Ok(val) => assert_eq!(val, DebugInfoOffset(0x0403_0201)), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_info_offset_32_incomplete() { - let buf = [0x01, 0x02]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_info_offset(buf, Format::Dwarf32) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_debug_info_offset_64() { - let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201); - let buf = section.get_contents().unwrap(); - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_info_offset(buf, Format::Dwarf64) { - Ok(val) => assert_eq!(val, DebugInfoOffset(0x0807_0605_0403_0201)), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_debug_info_offset_64_incomplete() { - let buf = [0x01, 0x02]; - let buf = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_debug_info_offset(buf, Format::Dwarf64) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_units() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let mut unit64 = UnitHeader { - encoding: Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let mut unit32 = UnitHeader { - encoding: Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut unit64) - .unit(&mut unit32); - let buf = section.get_contents().unwrap(); - - let debug_info = DebugInfo::new(&buf, LittleEndian); - let mut units = debug_info.units(); - - assert_eq!(units.next(), Ok(Some(unit64))); - assert_eq!(units.next(), Ok(Some(unit32))); - assert_eq!(units.next(), Ok(None)); - } - - #[test] - fn test_unit_version_unknown_version() { - let buf = [0x02, 0x00, 0x00, 0x00, 0xab, 0xcd]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_unit_header(rest, DebugInfoOffset(0).into()) { - Err(Error::UnknownVersion(0xcdab)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - - let buf = [0x02, 0x00, 0x00, 0x00, 0x1, 0x0]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_unit_header(rest, DebugInfoOffset(0).into()) { - Err(Error::UnknownVersion(1)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_unit_version_incomplete() { - let buf = [0x01, 0x00, 0x00, 0x00, 0x04]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_unit_header(rest, DebugInfoOffset(0).into()) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_partial_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Partial, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_partial_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Partial, - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_skeleton_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)), - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_skeleton_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)), - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_split_compilation_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 4, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)), - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_split_compilation_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)), - debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_type_offset_32_ok() { - let buf = [0x12, 0x34, 0x56, 0x78, 0x00]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_type_offset(rest, Format::Dwarf32) { - Ok(offset) => { - assert_eq!(rest.len(), 1); - assert_eq!(UnitOffset(0x7856_3412), offset); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_type_offset_64_ok() { - let buf = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0x00]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_type_offset(rest, Format::Dwarf64) { - Ok(offset) => { - assert_eq!(rest.len(), 1); - assert_eq!(UnitOffset(0xffde_bc9a_7856_3412), offset); - } - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } - - #[test] - fn test_parse_type_offset_incomplete() { - // Need at least 4 bytes. - let buf = [0xff, 0xff, 0xff]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - match parse_type_offset(rest, Format::Dwarf32) { - Err(Error::UnexpectedEof(_)) => assert!(true), - otherwise => panic!("Unexpected result: {:?}", otherwise), - }; - } - - #[test] - fn test_parse_type_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugTypesOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugTypesOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_type_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 4, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412_7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugTypesOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugTypesOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_type_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_type_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412_7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - fn test_parse_v5_split_type_unit_header_32_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::SplitType { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_v5_split_type_unit_header_64_ok() { - let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let encoding = Encoding { - format: Format::Dwarf64, - version: 5, - address_size: 8, - }; - let mut expected_unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::SplitType { - type_signature: DebugTypeSignature(0xdead_beef_dead_beef), - type_offset: UnitOffset(0x7856_3412_7856_3412), - }, - debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(expected_rest, LittleEndian), - }; - let section = Section::with_endian(Endian::Little) - .unit(&mut expected_unit) - .append_bytes(expected_rest); - let buf = section.get_contents().unwrap(); - let rest = &mut EndianSlice::new(&buf, LittleEndian); - - assert_eq!( - parse_unit_header(rest, DebugInfoOffset(0).into()), - Ok(expected_unit) - ); - assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); - } - - fn section_contents<F>(f: F) -> Vec<u8> - where - F: Fn(Section) -> Section, - { - f(Section::with_endian(Endian::Little)) - .get_contents() - .unwrap() - } - - #[test] - fn test_attribute_value() { - let mut unit = test_parse_attribute_unit_default(); - let endian = unit.entries_buf.endian(); - - let block_data = &[1, 2, 3, 4]; - let buf = section_contents(|s| s.uleb(block_data.len() as u64).append_bytes(block_data)); - let block = EndianSlice::new(&buf, endian); - - let buf = section_contents(|s| s.L32(0x0102_0304)); - let data4 = EndianSlice::new(&buf, endian); - - let buf = section_contents(|s| s.L64(0x0102_0304_0506_0708)); - let data8 = EndianSlice::new(&buf, endian); - - let tests = [ - ( - Format::Dwarf32, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_block, - block, - AttributeValue::Block(EndianSlice::new(block_data, endian)), - AttributeValue::Exprloc(Expression(EndianSlice::new(block_data, endian))), - ), - ( - Format::Dwarf32, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_data4, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)), - ), - ( - Format::Dwarf64, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_data4, - data4, - AttributeValue::Data4(0x0102_0304), - AttributeValue::Udata(0x0102_0304), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_data_member_location, - constants::DW_FORM_data4, - data4, - AttributeValue::Data4(0x0102_0304), - AttributeValue::Udata(0x0102_0304), - ), - ( - Format::Dwarf32, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_data8, - data8, - AttributeValue::Data8(0x0102_0304_0506_0708), - AttributeValue::Udata(0x0102_0304_0506_0708), - ), - #[cfg(target_pointer_width = "64")] - ( - Format::Dwarf64, - 2, - constants::DW_AT_data_member_location, - constants::DW_FORM_data8, - data8, - AttributeValue::SecOffset(0x0102_0304_0506_0708), - AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)), - ), - ( - Format::Dwarf64, - 4, - constants::DW_AT_data_member_location, - constants::DW_FORM_data8, - data8, - AttributeValue::Data8(0x0102_0304_0506_0708), - AttributeValue::Udata(0x0102_0304_0506_0708), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_location, - constants::DW_FORM_data4, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)), - ), - #[cfg(target_pointer_width = "64")] - ( - Format::Dwarf64, - 4, - constants::DW_AT_location, - constants::DW_FORM_data8, - data8, - AttributeValue::SecOffset(0x0102_0304_0506_0708), - AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_str_offsets_base, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(0x0102_0304)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_stmt_list, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugLineRef(DebugLineOffset(0x0102_0304)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_addr_base, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugAddrBase(DebugAddrBase(0x0102_0304)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_rnglists_base, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugRngListsBase(DebugRngListsBase(0x0102_0304)), - ), - ( - Format::Dwarf32, - 4, - constants::DW_AT_loclists_base, - constants::DW_FORM_sec_offset, - data4, - AttributeValue::SecOffset(0x0102_0304), - AttributeValue::DebugLocListsBase(DebugLocListsBase(0x0102_0304)), - ), - ]; - - for test in tests.iter() { - let (format, version, name, form, mut input, expect_raw, expect_value) = *test; - unit.encoding.format = format; - unit.encoding.version = version; - let spec = AttributeSpecification::new(name, form, None); - let attribute = - parse_attribute(&mut input, unit.encoding(), spec).expect("Should parse attribute"); - assert_eq!(attribute.raw_value(), expect_raw); - assert_eq!(attribute.value(), expect_value); - } - } - - #[test] - fn test_attribute_udata_sdata_value() { - let tests: &[( - AttributeValue<EndianSlice<LittleEndian>>, - Option<u64>, - Option<i64>, - )] = &[ - (AttributeValue::Data1(1), Some(1), Some(1)), - ( - AttributeValue::Data1(core::u8::MAX), - Some(u64::from(std::u8::MAX)), - Some(-1), - ), - (AttributeValue::Data2(1), Some(1), Some(1)), - ( - AttributeValue::Data2(core::u16::MAX), - Some(u64::from(std::u16::MAX)), - Some(-1), - ), - (AttributeValue::Data4(1), Some(1), Some(1)), - ( - AttributeValue::Data4(core::u32::MAX), - Some(u64::from(std::u32::MAX)), - Some(-1), - ), - (AttributeValue::Data8(1), Some(1), Some(1)), - ( - AttributeValue::Data8(core::u64::MAX), - Some(core::u64::MAX), - Some(-1), - ), - (AttributeValue::Sdata(1), Some(1), Some(1)), - (AttributeValue::Sdata(-1), None, Some(-1)), - (AttributeValue::Udata(1), Some(1), Some(1)), - (AttributeValue::Udata(1u64 << 63), Some(1u64 << 63), None), - ]; - for test in tests.iter() { - let (value, expect_udata, expect_sdata) = *test; - let attribute = Attribute { - name: DW_AT_data_member_location, - value, - }; - assert_eq!(attribute.udata_value(), expect_udata); - assert_eq!(attribute.sdata_value(), expect_sdata); - } - } - - fn test_parse_attribute_unit<Endian>( - address_size: u8, - format: Format, - endian: Endian, - ) -> UnitHeader<EndianSlice<'static, Endian>> - where - Endian: Endianity, - { - let encoding = Encoding { - format, - version: 4, - address_size, - }; - UnitHeader::new( - encoding, - 7, - UnitType::Compilation, - DebugAbbrevOffset(0x0807_0605), - DebugInfoOffset(0).into(), - EndianSlice::new(&[], endian), - ) - } - - fn test_parse_attribute_unit_default() -> UnitHeader<EndianSlice<'static, LittleEndian>> { - test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian) - } - - fn test_parse_attribute<'input, Endian>( - buf: &'input [u8], - len: usize, - unit: &UnitHeader<EndianSlice<'input, Endian>>, - form: constants::DwForm, - value: AttributeValue<EndianSlice<'input, Endian>>, - ) where - Endian: Endianity, - { - let spec = AttributeSpecification::new(constants::DW_AT_low_pc, form, None); - - let expect = Attribute { - name: constants::DW_AT_low_pc, - value, - }; - - let rest = &mut EndianSlice::new(buf, Endian::default()); - match parse_attribute(rest, unit.encoding(), spec) { - Ok(attr) => { - assert_eq!(attr, expect); - assert_eq!(*rest, EndianSlice::new(&buf[len..], Endian::default())); - if let Some(size) = spec.size(unit) { - assert_eq!(rest.len() + size, buf.len()); - } - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - }; - } - - #[test] - fn test_parse_attribute_addr() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_addr; - let value = AttributeValue::Addr(0x0403_0201); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addr8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; - let unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_addr; - let value = AttributeValue::Addr(0x0807_0605_0403_0201); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_block1() { - // Length of data (3), three bytes of data, two bytes of left over input. - let buf = [0x03, 0x09, 0x09, 0x09, 0x00, 0x00]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_block1; - let value = AttributeValue::Block(EndianSlice::new(&buf[1..4], LittleEndian)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_block2() { - // Two byte length of data (2), two bytes of data, two bytes of left over input. - let buf = [0x02, 0x00, 0x09, 0x09, 0x00, 0x00]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_block2; - let value = AttributeValue::Block(EndianSlice::new(&buf[2..4], LittleEndian)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_block4() { - // Four byte length of data (2), two bytes of data, no left over input. - let buf = [0x02, 0x00, 0x00, 0x00, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_block4; - let value = AttributeValue::Block(EndianSlice::new(&buf[4..], LittleEndian)); - test_parse_attribute(&buf, 6, &unit, form, value); - } - - #[test] - fn test_parse_attribute_block() { - // LEB length of data (2, one byte), two bytes of data, no left over input. - let buf = [0x02, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_block; - let value = AttributeValue::Block(EndianSlice::new(&buf[1..], LittleEndian)); - test_parse_attribute(&buf, 3, &unit, form, value); - } - - #[test] - fn test_parse_attribute_data1() { - let buf = [0x03]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_data1; - let value = AttributeValue::Data1(0x03); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_data2() { - let buf = [0x02, 0x01, 0x0]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_data2; - let value = AttributeValue::Data2(0x0102); - test_parse_attribute(&buf, 2, &unit, form, value); - } - - #[test] - fn test_parse_attribute_data4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_data4; - let value = AttributeValue::Data4(0x0403_0201); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_data8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_data8; - let value = AttributeValue::Data8(0x0807_0605_0403_0201); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_udata() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_udata; - let value = AttributeValue::Udata(4097); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_sdata() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::signed(&mut writable, -4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_sdata; - let value = AttributeValue::Sdata(-4097); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_exprloc() { - // LEB length of data (2, one byte), two bytes of data, one byte left over input. - let buf = [0x02, 0x99, 0x99, 0x11]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_exprloc; - let value = AttributeValue::Exprloc(Expression(EndianSlice::new(&buf[1..3], LittleEndian))); - test_parse_attribute(&buf, 3, &unit, form, value); - } - - #[test] - fn test_parse_attribute_flag_true() { - let buf = [0x42]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_flag; - let value = AttributeValue::Flag(true); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_flag_false() { - let buf = [0x00]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_flag; - let value = AttributeValue::Flag(false); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_flag_present() { - let buf = [0x01, 0x02, 0x03, 0x04]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_flag_present; - let value = AttributeValue::Flag(true); - // DW_FORM_flag_present does not consume any bytes of the input stream. - test_parse_attribute(&buf, 0, &unit, form, value); - } - - #[test] - fn test_parse_attribute_sec_offset_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_sec_offset; - let value = AttributeValue::SecOffset(0x0403_0201); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_sec_offset_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_sec_offset; - let value = AttributeValue::SecOffset(0x0807_0605_0403_0201); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_ref1() { - let buf = [0x03]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref1; - let value = AttributeValue::UnitRef(UnitOffset(3)); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_ref2() { - let buf = [0x02, 0x01, 0x0]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref2; - let value = AttributeValue::UnitRef(UnitOffset(258)); - test_parse_attribute(&buf, 2, &unit, form, value); - } - - #[test] - fn test_parse_attribute_ref4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref4; - let value = AttributeValue::UnitRef(UnitOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_ref8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref8; - let value = AttributeValue::UnitRef(UnitOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_ref_sup4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref_sup4; - let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_ref_sup8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref_sup8; - let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_refudata() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref_udata; - let value = AttributeValue::UnitRef(UnitOffset(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_refaddr_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_ref_addr; - let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_refaddr_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_ref_addr; - let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_refaddr_version2() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let mut unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - unit.encoding.version = 2; - let form = constants::DW_FORM_ref_addr; - let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_refaddr8_version2() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let mut unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian); - unit.encoding.version = 2; - let form = constants::DW_FORM_ref_addr; - let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_gnu_ref_alt_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_GNU_ref_alt; - let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_gnu_ref_alt_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_GNU_ref_alt; - let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_refsig8() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_ref_sig8; - let value = AttributeValue::DebugTypesRef(DebugTypeSignature(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_string() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x0, 0x99, 0x99]; - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_string; - let value = AttributeValue::String(EndianSlice::new(&buf[..5], LittleEndian)); - test_parse_attribute(&buf, 6, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strp_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_strp; - let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_strp_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strp; - let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strp_sup_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_strp_sup; - let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_strp_sup_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strp_sup; - let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_gnu_strp_alt_32() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); - let form = constants::DW_FORM_GNU_strp_alt; - let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_parse_attribute_gnu_strp_alt_64() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_GNU_strp_alt; - let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201)); - test_parse_attribute(&buf, 8, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_strx; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx1() { - let buf = [0x01, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strx1; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x01)); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx2() { - let buf = [0x01, 0x02, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strx2; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0201)); - test_parse_attribute(&buf, 2, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx3() { - let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strx3; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x03_0201)); - test_parse_attribute(&buf, 3, &unit, form, value); - } - - #[test] - fn test_parse_attribute_strx4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_strx4; - let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_addrx; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx1() { - let buf = [0x01, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_addrx1; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x01)); - test_parse_attribute(&buf, 1, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx2() { - let buf = [0x01, 0x02, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_addrx2; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0201)); - test_parse_attribute(&buf, 2, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx3() { - let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_addrx3; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x03_0201)); - test_parse_attribute(&buf, 3, &unit, form, value); - } - - #[test] - fn test_parse_attribute_addrx4() { - let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; - let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); - let form = constants::DW_FORM_addrx4; - let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0403_0201)); - test_parse_attribute(&buf, 4, &unit, form, value); - } - - #[test] - fn test_parse_attribute_loclistx() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_loclistx; - let value = AttributeValue::DebugLocListsIndex(DebugLocListsIndex(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_rnglistx() { - let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, 4097).expect("should write ok") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_rnglistx; - let value = AttributeValue::DebugRngListsIndex(DebugRngListsIndex(4097)); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_indirect() { - let mut buf = [0; 100]; - - let bytes_written = { - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, constants::DW_FORM_udata.0.into()) - .expect("should write udata") - + leb128::write::unsigned(&mut writable, 9_999_999).expect("should write value") - }; - - let unit = test_parse_attribute_unit_default(); - let form = constants::DW_FORM_indirect; - let value = AttributeValue::Udata(9_999_999); - test_parse_attribute(&buf, bytes_written, &unit, form, value); - } - - #[test] - fn test_parse_attribute_indirect_implicit_const() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut buf = [0; 100]; - let mut writable = &mut buf[..]; - leb128::write::unsigned(&mut writable, constants::DW_FORM_implicit_const.0.into()) - .expect("should write implicit_const"); - - let input = &mut EndianSlice::new(&buf, LittleEndian); - let spec = - AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_indirect, None); - assert_eq!( - parse_attribute(input, encoding, spec), - Err(Error::InvalidImplicitConst) - ); - } - - #[test] - fn test_attrs_iter() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let unit = UnitHeader::new( - encoding, - 7, - UnitType::Compilation, - DebugAbbrevOffset(0x0807_0605), - DebugInfoOffset(0).into(), - EndianSlice::new(&[], LittleEndian), - ); - - let abbrev = Abbreviation::new( - 42, - constants::DW_TAG_subprogram, - constants::DW_CHILDREN_yes, - vec![ - AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None), - AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None), - AttributeSpecification::new( - constants::DW_AT_high_pc, - constants::DW_FORM_addr, - None, - ), - ] - .into(), - ); - - // "foo", 42, 1337, 4 dangling bytes of 0xaa where children would be - let buf = [ - 0x66, 0x6f, 0x6f, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x39, 0x05, 0x00, 0x00, 0xaa, 0xaa, - 0xaa, 0xaa, - ]; - - let entry = DebuggingInformationEntry { - offset: UnitOffset(0), - attrs_slice: EndianSlice::new(&buf, LittleEndian), - attrs_len: Cell::new(None), - abbrev: &abbrev, - unit: &unit, - }; - - let mut attrs = AttrsIter { - input: EndianSlice::new(&buf, LittleEndian), - attributes: abbrev.attributes(), - entry: &entry, - }; - - match attrs.next() { - Ok(Some(attr)) => { - assert_eq!( - attr, - Attribute { - name: constants::DW_AT_name, - value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)), - } - ); - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - - assert!(entry.attrs_len.get().is_none()); - - match attrs.next() { - Ok(Some(attr)) => { - assert_eq!( - attr, - Attribute { - name: constants::DW_AT_low_pc, - value: AttributeValue::Addr(0x2a), - } - ); - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - - assert!(entry.attrs_len.get().is_none()); - - match attrs.next() { - Ok(Some(attr)) => { - assert_eq!( - attr, - Attribute { - name: constants::DW_AT_high_pc, - value: AttributeValue::Addr(0x539), - } - ); - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - - assert!(entry.attrs_len.get().is_none()); - - assert!(attrs.next().expect("should parse next").is_none()); - assert!(entry.attrs_len.get().is_some()); - assert_eq!( - entry.attrs_len.get().expect("should have entry.attrs_len"), - buf.len() - 4 - ) - } - - #[test] - fn test_attrs_iter_incomplete() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let unit = UnitHeader::new( - encoding, - 7, - UnitType::Compilation, - DebugAbbrevOffset(0x0807_0605), - DebugInfoOffset(0).into(), - EndianSlice::new(&[], LittleEndian), - ); - - let abbrev = Abbreviation::new( - 42, - constants::DW_TAG_subprogram, - constants::DW_CHILDREN_yes, - vec![ - AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None), - AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None), - AttributeSpecification::new( - constants::DW_AT_high_pc, - constants::DW_FORM_addr, - None, - ), - ] - .into(), - ); - - // "foo" - let buf = [0x66, 0x6f, 0x6f, 0x00]; - - let entry = DebuggingInformationEntry { - offset: UnitOffset(0), - attrs_slice: EndianSlice::new(&buf, LittleEndian), - attrs_len: Cell::new(None), - abbrev: &abbrev, - unit: &unit, - }; - - let mut attrs = AttrsIter { - input: EndianSlice::new(&buf, LittleEndian), - attributes: abbrev.attributes(), - entry: &entry, - }; - - match attrs.next() { - Ok(Some(attr)) => { - assert_eq!( - attr, - Attribute { - name: constants::DW_AT_name, - value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)), - } - ); - } - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - - assert!(entry.attrs_len.get().is_none()); - - // Return error for incomplete attribute. - assert!(attrs.next().is_err()); - assert!(entry.attrs_len.get().is_none()); - - // Return error for all subsequent calls. - assert!(attrs.next().is_err()); - assert!(attrs.next().is_err()); - assert!(attrs.next().is_err()); - assert!(attrs.next().is_err()); - assert!(entry.attrs_len.get().is_none()); - } - - fn assert_entry_name<Endian>(entry: &DebuggingInformationEntry<EndianSlice<Endian>>, name: &str) - where - Endian: Endianity, - { - let value = entry - .attr_value(constants::DW_AT_name) - .expect("Should have parsed the name attribute") - .expect("Should have found the name attribute"); - - assert_eq!( - value, - AttributeValue::String(EndianSlice::new(name.as_bytes(), Endian::default())) - ); - } - - fn assert_current_name<Endian>(cursor: &EntriesCursor<EndianSlice<Endian>>, name: &str) - where - Endian: Endianity, - { - let entry = cursor.current().expect("Should have an entry result"); - assert_entry_name(entry, name); - } - - fn assert_next_entry<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>, name: &str) - where - Endian: Endianity, - { - cursor - .next_entry() - .expect("Should parse next entry") - .expect("Should have an entry"); - assert_current_name(cursor, name); - } - - fn assert_next_entry_null<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>) - where - Endian: Endianity, - { - cursor - .next_entry() - .expect("Should parse next entry") - .expect("Should have an entry"); - assert!(cursor.current().is_none()); - } - - fn assert_next_dfs<Endian>( - cursor: &mut EntriesCursor<EndianSlice<Endian>>, - name: &str, - depth: isize, - ) where - Endian: Endianity, - { - { - let (val, entry) = cursor - .next_dfs() - .expect("Should parse next dfs") - .expect("Should not be done with traversal"); - assert_eq!(val, depth); - assert_entry_name(entry, name); - } - assert_current_name(cursor, name); - } - - fn assert_next_sibling<Endian>(cursor: &mut EntriesCursor<EndianSlice<Endian>>, name: &str) - where - Endian: Endianity, - { - { - let entry = cursor - .next_sibling() - .expect("Should parse next sibling") - .expect("Should not be done with traversal"); - assert_entry_name(entry, name); - } - assert_current_name(cursor, name); - } - - fn assert_valid_sibling_ptr<Endian>(cursor: &EntriesCursor<EndianSlice<Endian>>) - where - Endian: Endianity, - { - let sibling_ptr = cursor - .current() - .expect("Should have current entry") - .attr_value(constants::DW_AT_sibling); - match sibling_ptr { - Ok(Some(AttributeValue::UnitRef(offset))) => { - cursor - .unit - .range_from(offset..) - .expect("Sibling offset should be valid"); - } - _ => panic!("Invalid sibling pointer {:?}", sibling_ptr), - } - } - - fn entries_cursor_tests_abbrev_buf() -> Vec<u8> { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev_null(); - section.get_contents().unwrap() - } - - fn entries_cursor_tests_debug_info_buf() -> Vec<u8> { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .die(1, |s| s.attr_string("001")) - .die(1, |s| s.attr_string("002")) - .die(1, |s| s.attr_string("003")) - .die_null() - .die_null() - .die(1, |s| s.attr_string("004")) - .die(1, |s| s.attr_string("005")) - .die_null() - .die(1, |s| s.attr_string("006")) - .die_null() - .die_null() - .die(1, |s| s.attr_string("007")) - .die(1, |s| s.attr_string("008")) - .die(1, |s| s.attr_string("009")) - .die_null() - .die_null() - .die_null() - .die(1, |s| s.attr_string("010")) - .die_null() - .die_null(); - let entries_buf = section.get_contents().unwrap(); - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }; - let section = Section::with_endian(Endian::Little).unit(&mut unit); - section.get_contents().unwrap() - } - - #[test] - fn test_cursor_next_entry_incomplete() { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .die(1, |s| s.attr_string("001")) - .die(1, |s| s.attr_string("002")) - .die(1, |s| s); - let entries_buf = section.get_contents().unwrap(); - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }; - let section = Section::with_endian(Endian::Little).unit(&mut unit); - let info_buf = §ion.get_contents().unwrap(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_entry(&mut cursor, "001"); - assert_next_entry(&mut cursor, "002"); - - { - // Entry code is present, but none of the attributes. - cursor - .next_entry() - .expect("Should parse next entry") - .expect("Should have an entry"); - let entry = cursor.current().expect("Should have an entry result"); - assert!(entry.attrs().next().is_err()); - } - - assert!(cursor.next_entry().is_err()); - assert!(cursor.next_entry().is_err()); - } - - #[test] - fn test_cursor_next_entry() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_entry(&mut cursor, "001"); - assert_next_entry(&mut cursor, "002"); - assert_next_entry(&mut cursor, "003"); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - assert_next_entry(&mut cursor, "004"); - assert_next_entry(&mut cursor, "005"); - assert_next_entry_null(&mut cursor); - assert_next_entry(&mut cursor, "006"); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - assert_next_entry(&mut cursor, "007"); - assert_next_entry(&mut cursor, "008"); - assert_next_entry(&mut cursor, "009"); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - assert_next_entry(&mut cursor, "010"); - assert_next_entry_null(&mut cursor); - assert_next_entry_null(&mut cursor); - - assert!(cursor - .next_entry() - .expect("Should parse next entry") - .is_none()); - assert!(cursor.current().is_none()); - } - - #[test] - fn test_cursor_next_dfs() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_dfs(&mut cursor, "001", 0); - assert_next_dfs(&mut cursor, "002", 1); - assert_next_dfs(&mut cursor, "003", 1); - assert_next_dfs(&mut cursor, "004", -1); - assert_next_dfs(&mut cursor, "005", 1); - assert_next_dfs(&mut cursor, "006", 0); - assert_next_dfs(&mut cursor, "007", -1); - assert_next_dfs(&mut cursor, "008", 1); - assert_next_dfs(&mut cursor, "009", 1); - assert_next_dfs(&mut cursor, "010", -2); - - assert!(cursor.next_dfs().expect("Should parse next dfs").is_none()); - assert!(cursor.current().is_none()); - } - - #[test] - fn test_cursor_next_sibling_no_sibling_ptr() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_dfs(&mut cursor, "001", 0); - - // Down to the first child of the root entry. - - assert_next_dfs(&mut cursor, "002", 1); - - // Now iterate all children of the root via `next_sibling`. - - assert_next_sibling(&mut cursor, "004"); - assert_next_sibling(&mut cursor, "007"); - assert_next_sibling(&mut cursor, "010"); - - // There should be no more siblings. - - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor.current().is_none()); - } - - #[test] - fn test_cursor_next_sibling_continuation() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - - assert_next_dfs(&mut cursor, "001", 0); - - // Down to the first child of the root entry. - - assert_next_dfs(&mut cursor, "002", 1); - - // Get the next sibling, then iterate its children - - assert_next_sibling(&mut cursor, "004"); - assert_next_dfs(&mut cursor, "005", 1); - assert_next_sibling(&mut cursor, "006"); - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - - // And we should be able to continue with the children of the root entry. - - assert_next_dfs(&mut cursor, "007", -1); - assert_next_sibling(&mut cursor, "010"); - - // There should be no more siblings. - - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor.current().is_none()); - } - - fn entries_cursor_sibling_abbrev_buf() -> Vec<u8> { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr(DW_AT_sibling, DW_FORM_ref1) - .abbrev_attr_null() - .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev_null(); - section.get_contents().unwrap() - } - - fn entries_cursor_sibling_entries_buf(header_size: usize) -> Vec<u8> { - let start = Label::new(); - let sibling004_ref = Label::new(); - let sibling004 = Label::new(); - let sibling009_ref = Label::new(); - let sibling009 = Label::new(); - - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .mark(&start) - .die(2, |s| s.attr_string("001")) - // Valid sibling attribute. - .die(1, |s| s.attr_string("002").D8(&sibling004_ref)) - // Invalid code to ensure the sibling attribute was used. - .die(10, |s| s.attr_string("003")) - .die_null() - .die_null() - .mark(&sibling004) - // Invalid sibling attribute. - .die(1, |s| s.attr_string("004").attr_ref1(255)) - .die(2, |s| s.attr_string("005")) - .die_null() - .die_null() - // Sibling attribute in child only. - .die(2, |s| s.attr_string("006")) - // Valid sibling attribute. - .die(1, |s| s.attr_string("007").D8(&sibling009_ref)) - // Invalid code to ensure the sibling attribute was used. - .die(10, |s| s.attr_string("008")) - .die_null() - .die_null() - .mark(&sibling009) - .die(2, |s| s.attr_string("009")) - .die_null() - .die_null() - // No sibling attribute. - .die(2, |s| s.attr_string("010")) - .die(2, |s| s.attr_string("011")) - .die_null() - .die_null() - .die_null(); - - let offset = header_size as u64 + (&sibling004 - &start) as u64; - sibling004_ref.set_const(offset); - - let offset = header_size as u64 + (&sibling009 - &start) as u64; - sibling009_ref.set_const(offset); - - section.get_contents().unwrap() - } - - fn test_cursor_next_sibling_with_ptr(cursor: &mut EntriesCursor<EndianSlice<LittleEndian>>) { - assert_next_dfs(cursor, "001", 0); - - // Down to the first child of the root. - - assert_next_dfs(cursor, "002", 1); - - // Now iterate all children of the root via `next_sibling`. - - assert_valid_sibling_ptr(&cursor); - assert_next_sibling(cursor, "004"); - assert_next_sibling(cursor, "006"); - assert_next_sibling(cursor, "010"); - - // There should be no more siblings. - - assert!(cursor - .next_sibling() - .expect("Should parse next sibling") - .is_none()); - assert!(cursor.current().is_none()); - } - - #[test] - fn test_debug_info_next_sibling_with_ptr() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&[], LittleEndian), - }; - let header_size = unit.size_of_header(); - let entries_buf = entries_cursor_sibling_entries_buf(header_size); - unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); - let section = Section::with_endian(Endian::Little).unit(&mut unit); - let info_buf = section.get_contents().unwrap(); - let debug_info = DebugInfo::new(&info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrev_buf = entries_cursor_sibling_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - test_cursor_next_sibling_with_ptr(&mut cursor); - } - - #[test] - fn test_debug_types_next_sibling_with_ptr() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0), - type_offset: UnitOffset(0), - }, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugTypesOffset(0).into(), - entries_buf: EndianSlice::new(&[], LittleEndian), - }; - let header_size = unit.size_of_header(); - let entries_buf = entries_cursor_sibling_entries_buf(header_size); - unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); - let section = Section::with_endian(Endian::Little).unit(&mut unit); - let info_buf = section.get_contents().unwrap(); - let debug_types = DebugTypes::new(&info_buf, LittleEndian); - - let unit = debug_types - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrev_buf = entries_cursor_sibling_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit.entries(&abbrevs); - test_cursor_next_sibling_with_ptr(&mut cursor); - } - - #[test] - fn test_entries_at_offset() { - let info_buf = &entries_cursor_tests_debug_info_buf(); - let debug_info = DebugInfo::new(info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); - let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut cursor = unit - .entries_at_offset(&abbrevs, UnitOffset(unit.header_size())) - .unwrap(); - assert_next_entry(&mut cursor, "001"); - - let cursor = unit.entries_at_offset(&abbrevs, UnitOffset(0)); - match cursor { - Err(Error::OffsetOutOfBounds) => {} - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - } - - fn entries_tree_tests_debug_abbrevs_buf() -> Vec<u8> { - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_no) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev_null() - .get_contents() - .unwrap(); - section - } - - fn entries_tree_tests_debug_info_buf(header_size: usize) -> (Vec<u8>, UnitOffset) { - let start = Label::new(); - let entry2 = Label::new(); - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .mark(&start) - .die(1, |s| s.attr_string("root")) - .die(1, |s| s.attr_string("1")) - .die(1, |s| s.attr_string("1a")) - .die_null() - .die(2, |s| s.attr_string("1b")) - .die_null() - .mark(&entry2) - .die(1, |s| s.attr_string("2")) - .die(1, |s| s.attr_string("2a")) - .die(1, |s| s.attr_string("2a1")) - .die_null() - .die_null() - .die(1, |s| s.attr_string("2b")) - .die(2, |s| s.attr_string("2b1")) - .die_null() - .die_null() - .die(1, |s| s.attr_string("3")) - .die(1, |s| s.attr_string("3a")) - .die(2, |s| s.attr_string("3a1")) - .die(2, |s| s.attr_string("3a2")) - .die_null() - .die(2, |s| s.attr_string("3b")) - .die_null() - .die(2, |s| s.attr_string("final")) - .die_null() - .get_contents() - .unwrap(); - let entry2 = UnitOffset(header_size + (&entry2 - &start) as usize); - (section, entry2) - } - - #[test] - fn test_entries_tree() { - fn assert_entry<'input, 'abbrev, 'unit, 'tree, Endian>( - node: Result< - Option<EntriesTreeNode<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>>>, - >, - name: &str, - ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>> - where - Endian: Endianity, - { - let node = node - .expect("Should parse entry") - .expect("Should have entry"); - assert_entry_name(node.entry(), name); - node.children() - } - - fn assert_null<E: Endianity>(node: Result<Option<EntriesTreeNode<EndianSlice<E>>>>) { - match node { - Ok(None) => {} - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - } - - let abbrevs_buf = entries_tree_tests_debug_abbrevs_buf(); - let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian); - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&[], LittleEndian), - }; - let header_size = unit.size_of_header(); - let (entries_buf, entry2) = entries_tree_tests_debug_info_buf(header_size); - unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian); - let info_buf = Section::with_endian(Endian::Little) - .unit(&mut unit) - .get_contents() - .unwrap(); - let debug_info = DebugInfo::new(&info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("Should parse unit") - .expect("and it should be some"); - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - let mut tree = unit - .entries_tree(&abbrevs, None) - .expect("Should have entries tree"); - - // Test we can restart iteration of the tree. - { - let mut iter = assert_entry(tree.root().map(Some), "root"); - assert_entry(iter.next(), "1"); - } - { - let mut iter = assert_entry(tree.root().map(Some), "root"); - assert_entry(iter.next(), "1"); - } - - let mut iter = assert_entry(tree.root().map(Some), "root"); - { - // Test iteration with children. - let mut iter = assert_entry(iter.next(), "1"); - { - // Test iteration with children flag, but no children. - let mut iter = assert_entry(iter.next(), "1a"); - assert_null(iter.next()); - assert_null(iter.next()); - } - { - // Test iteration without children flag. - let mut iter = assert_entry(iter.next(), "1b"); - assert_null(iter.next()); - assert_null(iter.next()); - } - assert_null(iter.next()); - assert_null(iter.next()); - } - { - // Test skipping over children. - let mut iter = assert_entry(iter.next(), "2"); - assert_entry(iter.next(), "2a"); - assert_entry(iter.next(), "2b"); - assert_null(iter.next()); - } - { - // Test skipping after partial iteration. - let mut iter = assert_entry(iter.next(), "3"); - { - let mut iter = assert_entry(iter.next(), "3a"); - assert_entry(iter.next(), "3a1"); - // Parent iter should be able to skip over "3a2". - } - assert_entry(iter.next(), "3b"); - assert_null(iter.next()); - } - assert_entry(iter.next(), "final"); - assert_null(iter.next()); - - // Test starting at an offset. - let mut tree = unit - .entries_tree(&abbrevs, Some(entry2)) - .expect("Should have entries tree"); - let mut iter = assert_entry(tree.root().map(Some), "2"); - assert_entry(iter.next(), "2a"); - assert_entry(iter.next(), "2b"); - assert_null(iter.next()); - } - - #[test] - fn test_entries_raw() { - fn assert_abbrev<'input, 'abbrev, 'unit, Endian>( - entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>, - tag: DwTag, - ) -> &'abbrev Abbreviation - where - Endian: Endianity, - { - let abbrev = entries - .read_abbreviation() - .expect("Should parse abbrev") - .expect("Should have abbrev"); - assert_eq!(abbrev.tag(), tag); - abbrev - } - - fn assert_null<'input, 'abbrev, 'unit, Endian>( - entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>, - ) where - Endian: Endianity, - { - match entries.read_abbreviation() { - Ok(None) => {} - otherwise => { - assert!(false, "Unexpected parse result = {:#?}", otherwise); - } - } - } - - fn assert_attr<'input, 'abbrev, 'unit, Endian>( - entries: &mut EntriesRaw<'abbrev, 'unit, EndianSlice<'input, Endian>>, - spec: Option<AttributeSpecification>, - name: DwAt, - value: &str, - ) where - Endian: Endianity, - { - let spec = spec.expect("Should have attribute specification"); - let attr = entries - .read_attribute(spec) - .expect("Should parse attribute"); - assert_eq!(attr.name(), name); - assert_eq!( - attr.value(), - AttributeValue::String(EndianSlice::new(value.as_bytes(), Endian::default())) - ); - } - - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr(DW_AT_linkage_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev(2, DW_TAG_variable, DW_CHILDREN_no) - .abbrev_attr(DW_AT_name, DW_FORM_string) - .abbrev_attr_null() - .abbrev_null(); - let abbrevs_buf = section.get_contents().unwrap(); - let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian); - - #[rustfmt::skip] - let section = Section::with_endian(Endian::Little) - .die(1, |s| s.attr_string("f1").attr_string("l1")) - .die(2, |s| s.attr_string("v1")) - .die(2, |s| s.attr_string("v2")) - .die(1, |s| s.attr_string("f2").attr_string("l2")) - .die_null() - .die_null(); - let entries_buf = section.get_contents().unwrap(); - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&entries_buf, LittleEndian), - }; - let section = Section::with_endian(Endian::Little).unit(&mut unit); - let info_buf = section.get_contents().unwrap(); - let debug_info = DebugInfo::new(&info_buf, LittleEndian); - - let unit = debug_info - .units() - .next() - .expect("should have a unit result") - .expect("and it should be ok"); - - let abbrevs = unit - .abbreviations(&debug_abbrev) - .expect("Should parse abbreviations"); - - let mut entries = unit - .entries_raw(&abbrevs, None) - .expect("Should have entries"); - - assert_eq!(entries.next_depth(), 0); - let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram); - let mut attrs = abbrev.attributes().iter().copied(); - assert_attr(&mut entries, attrs.next(), DW_AT_name, "f1"); - assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l1"); - assert!(attrs.next().is_none()); - - assert_eq!(entries.next_depth(), 1); - let abbrev = assert_abbrev(&mut entries, DW_TAG_variable); - let mut attrs = abbrev.attributes().iter().copied(); - assert_attr(&mut entries, attrs.next(), DW_AT_name, "v1"); - assert!(attrs.next().is_none()); - - assert_eq!(entries.next_depth(), 1); - let abbrev = assert_abbrev(&mut entries, DW_TAG_variable); - let mut attrs = abbrev.attributes().iter().copied(); - assert_attr(&mut entries, attrs.next(), DW_AT_name, "v2"); - assert!(attrs.next().is_none()); - - assert_eq!(entries.next_depth(), 1); - let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram); - let mut attrs = abbrev.attributes().iter().copied(); - assert_attr(&mut entries, attrs.next(), DW_AT_name, "f2"); - assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l2"); - assert!(attrs.next().is_none()); - - assert_eq!(entries.next_depth(), 2); - assert_null(&mut entries); - - assert_eq!(entries.next_depth(), 1); - assert_null(&mut entries); - - assert_eq!(entries.next_depth(), 0); - assert!(entries.is_empty()); - } - - #[test] - fn test_debug_info_offset() { - let padding = &[0; 10]; - let entries = &[0; 20]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(entries, LittleEndian), - }; - Section::with_endian(Endian::Little) - .append_bytes(padding) - .unit(&mut unit); - let offset = padding.len(); - let header_length = unit.size_of_header(); - let length = unit.length_including_self(); - assert_eq!(DebugInfoOffset(0).to_unit_offset(&unit), None); - assert_eq!(DebugInfoOffset(offset - 1).to_unit_offset(&unit), None); - assert_eq!(DebugInfoOffset(offset).to_unit_offset(&unit), None); - assert_eq!( - DebugInfoOffset(offset + header_length - 1).to_unit_offset(&unit), - None - ); - assert_eq!( - DebugInfoOffset(offset + header_length).to_unit_offset(&unit), - Some(UnitOffset(header_length)) - ); - assert_eq!( - DebugInfoOffset(offset + length - 1).to_unit_offset(&unit), - Some(UnitOffset(length - 1)) - ); - assert_eq!(DebugInfoOffset(offset + length).to_unit_offset(&unit), None); - assert_eq!( - UnitOffset(header_length).to_debug_info_offset(&unit), - Some(DebugInfoOffset(offset + header_length)) - ); - assert_eq!( - UnitOffset(length - 1).to_debug_info_offset(&unit), - Some(DebugInfoOffset(offset + length - 1)) - ); - } - - #[test] - fn test_debug_types_offset() { - let padding = &[0; 10]; - let entries = &[0; 20]; - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Type { - type_signature: DebugTypeSignature(0), - type_offset: UnitOffset(0), - }, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugTypesOffset(0).into(), - entries_buf: EndianSlice::new(entries, LittleEndian), - }; - Section::with_endian(Endian::Little) - .append_bytes(padding) - .unit(&mut unit); - let offset = padding.len(); - let header_length = unit.size_of_header(); - let length = unit.length_including_self(); - assert_eq!(DebugTypesOffset(0).to_unit_offset(&unit), None); - assert_eq!(DebugTypesOffset(offset - 1).to_unit_offset(&unit), None); - assert_eq!(DebugTypesOffset(offset).to_unit_offset(&unit), None); - assert_eq!( - DebugTypesOffset(offset + header_length - 1).to_unit_offset(&unit), - None - ); - assert_eq!( - DebugTypesOffset(offset + header_length).to_unit_offset(&unit), - Some(UnitOffset(header_length)) - ); - assert_eq!( - DebugTypesOffset(offset + length - 1).to_unit_offset(&unit), - Some(UnitOffset(length - 1)) - ); - assert_eq!( - DebugTypesOffset(offset + length).to_unit_offset(&unit), - None - ); - assert_eq!( - UnitOffset(header_length).to_debug_types_offset(&unit), - Some(DebugTypesOffset(offset + header_length)) - ); - assert_eq!( - UnitOffset(length - 1).to_debug_types_offset(&unit), - Some(DebugTypesOffset(offset + length - 1)) - ); - } - - #[test] - fn test_length_including_self() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let mut unit = UnitHeader { - encoding, - unit_length: 0, - unit_type: UnitType::Compilation, - debug_abbrev_offset: DebugAbbrevOffset(0), - unit_offset: DebugInfoOffset(0).into(), - entries_buf: EndianSlice::new(&[], LittleEndian), - }; - unit.encoding.format = Format::Dwarf32; - assert_eq!(unit.length_including_self(), 4); - unit.encoding.format = Format::Dwarf64; - assert_eq!(unit.length_including_self(), 12); - unit.unit_length = 10; - assert_eq!(unit.length_including_self(), 22); - } - - #[test] - fn test_parse_type_unit_abbrevs() { - let types_buf = [ - // Type unit header - 0x25, 0x00, 0x00, 0x00, // 32-bit unit length = 37 - 0x04, 0x00, // Version 4 - 0x00, 0x00, 0x00, 0x00, // debug_abbrev_offset - 0x04, // Address size - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Type signature - 0x01, 0x02, 0x03, 0x04, // Type offset - // DIEs - // Abbreviation code - 0x01, // Attribute of form DW_FORM_string = "foo\0" - 0x66, 0x6f, 0x6f, 0x00, // Children - // Abbreviation code - 0x01, // Attribute of form DW_FORM_string = "foo\0" - 0x66, 0x6f, 0x6f, 0x00, // Children - // Abbreviation code - 0x01, // Attribute of form DW_FORM_string = "foo\0" - 0x66, 0x6f, 0x6f, 0x00, // Children - 0x00, // End of children - 0x00, // End of children - 0x00, // End of children - ]; - let debug_types = DebugTypes::new(&types_buf, LittleEndian); - - let abbrev_buf = [ - // Code - 0x01, // DW_TAG_subprogram - 0x2e, // DW_CHILDREN_yes - 0x01, // Begin attributes - 0x03, // Attribute name = DW_AT_name - 0x08, // Attribute form = DW_FORM_string - 0x00, 0x00, // End attributes - 0x00, // Null terminator - ]; - - let get_some_type_unit = || debug_types.units().next().unwrap().unwrap(); - - let unit = get_some_type_unit(); - - let read_debug_abbrev_section_somehow = || &abbrev_buf; - let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); - let _abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap(); - } -} diff --git a/vendor/gimli/src/read/util.rs b/vendor/gimli/src/read/util.rs deleted file mode 100644 index 041ca5a..0000000 --- a/vendor/gimli/src/read/util.rs +++ /dev/null @@ -1,283 +0,0 @@ -#[cfg(feature = "read")] -use alloc::boxed::Box; -#[cfg(feature = "read")] -use alloc::vec::Vec; -use core::fmt; -use core::mem::MaybeUninit; -use core::ops; -use core::ptr; -use core::slice; - -mod sealed { - /// # Safety - /// Implementer must not modify the content in storage. - pub unsafe trait Sealed { - type Storage; - - fn new_storage() -> Self::Storage; - - fn grow(_storage: &mut Self::Storage, _additional: usize) -> Result<(), CapacityFull> { - Err(CapacityFull) - } - } - - #[derive(Clone, Copy, Debug)] - pub struct CapacityFull; -} - -use sealed::*; - -/// Marker trait for types that can be used as backing storage when a growable array type is needed. -/// -/// This trait is sealed and cannot be implemented for types outside this crate. -pub trait ArrayLike: Sealed { - /// Type of the elements being stored. - type Item; - - #[doc(hidden)] - fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<Self::Item>]; - - #[doc(hidden)] - fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<Self::Item>]; -} - -// Use macro since const generics can't be used due to MSRV. -macro_rules! impl_array { - () => {}; - ($n:literal $($rest:tt)*) => { - // SAFETY: does not modify the content in storage. - unsafe impl<T> Sealed for [T; $n] { - type Storage = [MaybeUninit<T>; $n]; - - fn new_storage() -> Self::Storage { - // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid. - unsafe { MaybeUninit::uninit().assume_init() } - } - } - - impl<T> ArrayLike for [T; $n] { - type Item = T; - - fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] { - storage - } - - fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] { - storage - } - } - - impl_array!($($rest)*); - } -} - -#[cfg(feature = "read")] -macro_rules! impl_box { - () => {}; - ($n:literal $($rest:tt)*) => { - // SAFETY: does not modify the content in storage. - unsafe impl<T> Sealed for Box<[T; $n]> { - type Storage = Box<[MaybeUninit<T>; $n]>; - - fn new_storage() -> Self::Storage { - // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid. - Box::new(unsafe { MaybeUninit::uninit().assume_init() }) - } - } - - impl<T> ArrayLike for Box<[T; $n]> { - type Item = T; - - fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] { - &storage[..] - } - - fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] { - &mut storage[..] - } - } - - impl_box!($($rest)*); - } -} - -impl_array!(0 1 2 3 4 8 16 32 64 128 192); -#[cfg(feature = "read")] -impl_box!(0 1 2 3 4 8 16 32 64 128 192); - -#[cfg(feature = "read")] -unsafe impl<T> Sealed for Vec<T> { - type Storage = Box<[MaybeUninit<T>]>; - - fn new_storage() -> Self::Storage { - Box::new([]) - } - - fn grow(storage: &mut Self::Storage, additional: usize) -> Result<(), CapacityFull> { - let mut vec: Vec<_> = core::mem::replace(storage, Box::new([])).into(); - vec.reserve(additional); - // SAFETY: This is a `Vec` of `MaybeUninit`. - unsafe { vec.set_len(vec.capacity()) }; - *storage = vec.into_boxed_slice(); - Ok(()) - } -} - -#[cfg(feature = "read")] -impl<T> ArrayLike for Vec<T> { - type Item = T; - - fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] { - storage - } - - fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] { - storage - } -} - -pub(crate) struct ArrayVec<A: ArrayLike> { - storage: A::Storage, - len: usize, -} - -impl<A: ArrayLike> ArrayVec<A> { - pub fn new() -> Self { - Self { - storage: A::new_storage(), - len: 0, - } - } - - pub fn clear(&mut self) { - let ptr: *mut [A::Item] = &mut **self; - // Set length first so the type invariant is upheld even if `drop_in_place` panicks. - self.len = 0; - // SAFETY: `ptr` contains valid elements only and we "forget" them by setting the length. - unsafe { ptr::drop_in_place(ptr) }; - } - - pub fn try_push(&mut self, value: A::Item) -> Result<(), CapacityFull> { - let mut storage = A::as_mut_slice(&mut self.storage); - if self.len >= storage.len() { - A::grow(&mut self.storage, 1)?; - storage = A::as_mut_slice(&mut self.storage); - } - - storage[self.len] = MaybeUninit::new(value); - self.len += 1; - Ok(()) - } - - pub fn try_insert(&mut self, index: usize, element: A::Item) -> Result<(), CapacityFull> { - assert!(index <= self.len); - - let mut storage = A::as_mut_slice(&mut self.storage); - if self.len >= storage.len() { - A::grow(&mut self.storage, 1)?; - storage = A::as_mut_slice(&mut self.storage); - } - - // SAFETY: storage[index] is filled later. - unsafe { - let p = storage.as_mut_ptr().add(index); - core::ptr::copy(p as *const _, p.add(1), self.len - index); - } - storage[index] = MaybeUninit::new(element); - self.len += 1; - Ok(()) - } - - pub fn pop(&mut self) -> Option<A::Item> { - if self.len == 0 { - None - } else { - self.len -= 1; - // SAFETY: this element is valid and we "forget" it by setting the length. - Some(unsafe { A::as_slice(&self.storage)[self.len].as_ptr().read() }) - } - } - - pub fn swap_remove(&mut self, index: usize) -> A::Item { - assert!(self.len > 0); - A::as_mut_slice(&mut self.storage).swap(index, self.len - 1); - self.pop().unwrap() - } -} - -#[cfg(feature = "read")] -impl<T> ArrayVec<Vec<T>> { - pub fn into_vec(mut self) -> Vec<T> { - let len = core::mem::replace(&mut self.len, 0); - let storage = core::mem::replace(&mut self.storage, Box::new([])); - let slice = Box::leak(storage); - debug_assert!(len <= slice.len()); - // SAFETY: valid elements. - unsafe { Vec::from_raw_parts(slice.as_mut_ptr() as *mut T, len, slice.len()) } - } -} - -impl<A: ArrayLike> Drop for ArrayVec<A> { - fn drop(&mut self) { - self.clear(); - } -} - -impl<A: ArrayLike> Default for ArrayVec<A> { - fn default() -> Self { - Self::new() - } -} - -impl<A: ArrayLike> ops::Deref for ArrayVec<A> { - type Target = [A::Item]; - - fn deref(&self) -> &[A::Item] { - let slice = &A::as_slice(&self.storage); - debug_assert!(self.len <= slice.len()); - // SAFETY: valid elements. - unsafe { slice::from_raw_parts(slice.as_ptr() as _, self.len) } - } -} - -impl<A: ArrayLike> ops::DerefMut for ArrayVec<A> { - fn deref_mut(&mut self) -> &mut [A::Item] { - let slice = &mut A::as_mut_slice(&mut self.storage); - debug_assert!(self.len <= slice.len()); - // SAFETY: valid elements. - unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr() as _, self.len) } - } -} - -impl<A: ArrayLike> Clone for ArrayVec<A> -where - A::Item: Clone, -{ - fn clone(&self) -> Self { - let mut new = Self::default(); - for value in &**self { - new.try_push(value.clone()).unwrap(); - } - new - } -} - -impl<A: ArrayLike> PartialEq for ArrayVec<A> -where - A::Item: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - **self == **other - } -} - -impl<A: ArrayLike> Eq for ArrayVec<A> where A::Item: Eq {} - -impl<A: ArrayLike> fmt::Debug for ArrayVec<A> -where - A::Item: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} diff --git a/vendor/gimli/src/read/value.rs b/vendor/gimli/src/read/value.rs deleted file mode 100644 index 77b08ed..0000000 --- a/vendor/gimli/src/read/value.rs +++ /dev/null @@ -1,1621 +0,0 @@ -//! Definitions for values used in DWARF expressions. - -use crate::constants; -#[cfg(feature = "read")] -use crate::read::{AttributeValue, DebuggingInformationEntry}; -use crate::read::{Error, Reader, Result}; - -/// Convert a u64 to an i64, with sign extension if required. -/// -/// This is primarily used when needing to treat `Value::Generic` -/// as a signed value. -#[inline] -fn sign_extend(value: u64, mask: u64) -> i64 { - let value = (value & mask) as i64; - let sign = ((mask >> 1) + 1) as i64; - (value ^ sign).wrapping_sub(sign) -} - -#[inline] -fn mask_bit_size(addr_mask: u64) -> u32 { - 64 - addr_mask.leading_zeros() -} - -/// The type of an entry on the DWARF stack. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ValueType { - /// The generic type, which is address-sized and of unspecified sign, - /// as specified in the DWARF 5 standard, section 2.5.1. - /// This type is also used to represent address base types. - Generic, - /// Signed 8-bit integer type. - I8, - /// Unsigned 8-bit integer type. - U8, - /// Signed 16-bit integer type. - I16, - /// Unsigned 16-bit integer type. - U16, - /// Signed 32-bit integer type. - I32, - /// Unsigned 32-bit integer type. - U32, - /// Signed 64-bit integer type. - I64, - /// Unsigned 64-bit integer type. - U64, - /// 32-bit floating point type. - F32, - /// 64-bit floating point type. - F64, -} - -/// The value of an entry on the DWARF stack. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Value { - /// A generic value, which is address-sized and of unspecified sign. - Generic(u64), - /// A signed 8-bit integer value. - I8(i8), - /// An unsigned 8-bit integer value. - U8(u8), - /// A signed 16-bit integer value. - I16(i16), - /// An unsigned 16-bit integer value. - U16(u16), - /// A signed 32-bit integer value. - I32(i32), - /// An unsigned 32-bit integer value. - U32(u32), - /// A signed 64-bit integer value. - I64(i64), - /// An unsigned 64-bit integer value. - U64(u64), - /// A 32-bit floating point value. - F32(f32), - /// A 64-bit floating point value. - F64(f64), -} - -impl ValueType { - /// The size in bits of a value for this type. - pub fn bit_size(self, addr_mask: u64) -> u32 { - match self { - ValueType::Generic => mask_bit_size(addr_mask), - ValueType::I8 | ValueType::U8 => 8, - ValueType::I16 | ValueType::U16 => 16, - ValueType::I32 | ValueType::U32 | ValueType::F32 => 32, - ValueType::I64 | ValueType::U64 | ValueType::F64 => 64, - } - } - - /// Construct a `ValueType` from the attributes of a base type DIE. - pub fn from_encoding(encoding: constants::DwAte, byte_size: u64) -> Option<ValueType> { - Some(match (encoding, byte_size) { - (constants::DW_ATE_signed, 1) => ValueType::I8, - (constants::DW_ATE_signed, 2) => ValueType::I16, - (constants::DW_ATE_signed, 4) => ValueType::I32, - (constants::DW_ATE_signed, 8) => ValueType::I64, - (constants::DW_ATE_unsigned, 1) => ValueType::U8, - (constants::DW_ATE_unsigned, 2) => ValueType::U16, - (constants::DW_ATE_unsigned, 4) => ValueType::U32, - (constants::DW_ATE_unsigned, 8) => ValueType::U64, - (constants::DW_ATE_float, 4) => ValueType::F32, - (constants::DW_ATE_float, 8) => ValueType::F64, - _ => return None, - }) - } - - /// Construct a `ValueType` from a base type DIE. - #[cfg(feature = "read")] - pub fn from_entry<R: Reader>( - entry: &DebuggingInformationEntry<R>, - ) -> Result<Option<ValueType>> { - if entry.tag() != constants::DW_TAG_base_type { - return Ok(None); - } - let mut encoding = None; - let mut byte_size = None; - let mut endianity = constants::DW_END_default; - let mut attrs = entry.attrs(); - while let Some(attr) = attrs.next()? { - match attr.name() { - constants::DW_AT_byte_size => byte_size = attr.udata_value(), - constants::DW_AT_encoding => { - if let AttributeValue::Encoding(x) = attr.value() { - encoding = Some(x); - } - } - constants::DW_AT_endianity => { - if let AttributeValue::Endianity(x) = attr.value() { - endianity = x; - } - } - _ => {} - } - } - - if endianity != constants::DW_END_default { - // TODO: we could check if it matches the reader endianity, - // but normally it would use DW_END_default in that case. - return Ok(None); - } - - if let (Some(encoding), Some(byte_size)) = (encoding, byte_size) { - Ok(ValueType::from_encoding(encoding, byte_size)) - } else { - Ok(None) - } - } -} - -impl Value { - /// Return the `ValueType` corresponding to this `Value`. - pub fn value_type(&self) -> ValueType { - match *self { - Value::Generic(_) => ValueType::Generic, - Value::I8(_) => ValueType::I8, - Value::U8(_) => ValueType::U8, - Value::I16(_) => ValueType::I16, - Value::U16(_) => ValueType::U16, - Value::I32(_) => ValueType::I32, - Value::U32(_) => ValueType::U32, - Value::I64(_) => ValueType::I64, - Value::U64(_) => ValueType::U64, - Value::F32(_) => ValueType::F32, - Value::F64(_) => ValueType::F64, - } - } - - /// Read a `Value` with the given `value_type` from a `Reader`. - pub fn parse<R: Reader>(value_type: ValueType, mut bytes: R) -> Result<Value> { - let value = match value_type { - ValueType::I8 => Value::I8(bytes.read_i8()?), - ValueType::U8 => Value::U8(bytes.read_u8()?), - ValueType::I16 => Value::I16(bytes.read_i16()?), - ValueType::U16 => Value::U16(bytes.read_u16()?), - ValueType::I32 => Value::I32(bytes.read_i32()?), - ValueType::U32 => Value::U32(bytes.read_u32()?), - ValueType::I64 => Value::I64(bytes.read_i64()?), - ValueType::U64 => Value::U64(bytes.read_u64()?), - ValueType::F32 => Value::F32(bytes.read_f32()?), - ValueType::F64 => Value::F64(bytes.read_f64()?), - _ => return Err(Error::UnsupportedTypeOperation), - }; - Ok(value) - } - - /// Convert a `Value` to a `u64`. - /// - /// The `ValueType` of `self` must be integral. - /// Values are sign extended if the source value is signed. - pub fn to_u64(self, addr_mask: u64) -> Result<u64> { - let value = match self { - Value::Generic(value) => value & addr_mask, - Value::I8(value) => value as u64, - Value::U8(value) => u64::from(value), - Value::I16(value) => value as u64, - Value::U16(value) => u64::from(value), - Value::I32(value) => value as u64, - Value::U32(value) => u64::from(value), - Value::I64(value) => value as u64, - Value::U64(value) => value as u64, - _ => return Err(Error::IntegralTypeRequired), - }; - Ok(value) - } - - /// Create a `Value` with the given `value_type` from a `u64` value. - /// - /// The `value_type` may be integral or floating point. - /// The result is truncated if the `u64` value does - /// not fit the bounds of the `value_type`. - pub fn from_u64(value_type: ValueType, value: u64) -> Result<Value> { - let value = match value_type { - ValueType::Generic => Value::Generic(value), - ValueType::I8 => Value::I8(value as i8), - ValueType::U8 => Value::U8(value as u8), - ValueType::I16 => Value::I16(value as i16), - ValueType::U16 => Value::U16(value as u16), - ValueType::I32 => Value::I32(value as i32), - ValueType::U32 => Value::U32(value as u32), - ValueType::I64 => Value::I64(value as i64), - ValueType::U64 => Value::U64(value), - ValueType::F32 => Value::F32(value as f32), - ValueType::F64 => Value::F64(value as f64), - }; - Ok(value) - } - - /// Create a `Value` with the given `value_type` from a `f32` value. - /// - /// The `value_type` may be integral or floating point. - /// The result is not defined if the `f32` value does - /// not fit the bounds of the `value_type`. - fn from_f32(value_type: ValueType, value: f32) -> Result<Value> { - let value = match value_type { - ValueType::Generic => Value::Generic(value as u64), - ValueType::I8 => Value::I8(value as i8), - ValueType::U8 => Value::U8(value as u8), - ValueType::I16 => Value::I16(value as i16), - ValueType::U16 => Value::U16(value as u16), - ValueType::I32 => Value::I32(value as i32), - ValueType::U32 => Value::U32(value as u32), - ValueType::I64 => Value::I64(value as i64), - ValueType::U64 => Value::U64(value as u64), - ValueType::F32 => Value::F32(value), - ValueType::F64 => Value::F64(f64::from(value)), - }; - Ok(value) - } - - /// Create a `Value` with the given `value_type` from a `f64` value. - /// - /// The `value_type` may be integral or floating point. - /// The result is not defined if the `f64` value does - /// not fit the bounds of the `value_type`. - fn from_f64(value_type: ValueType, value: f64) -> Result<Value> { - let value = match value_type { - ValueType::Generic => Value::Generic(value as u64), - ValueType::I8 => Value::I8(value as i8), - ValueType::U8 => Value::U8(value as u8), - ValueType::I16 => Value::I16(value as i16), - ValueType::U16 => Value::U16(value as u16), - ValueType::I32 => Value::I32(value as i32), - ValueType::U32 => Value::U32(value as u32), - ValueType::I64 => Value::I64(value as i64), - ValueType::U64 => Value::U64(value as u64), - ValueType::F32 => Value::F32(value as f32), - ValueType::F64 => Value::F64(value), - }; - Ok(value) - } - - /// Convert a `Value` to the given `value_type`. - /// - /// When converting between integral types, the result is truncated - /// if the source value does not fit the bounds of the `value_type`. - /// When converting from floating point types, the result is not defined - /// if the source value does not fit the bounds of the `value_type`. - /// - /// This corresponds to the DWARF `DW_OP_convert` operation. - pub fn convert(self, value_type: ValueType, addr_mask: u64) -> Result<Value> { - match self { - Value::F32(value) => Value::from_f32(value_type, value), - Value::F64(value) => Value::from_f64(value_type, value), - _ => Value::from_u64(value_type, self.to_u64(addr_mask)?), - } - } - - /// Reinterpret the bits in a `Value` as the given `value_type`. - /// - /// The source and result value types must have equal sizes. - /// - /// This corresponds to the DWARF `DW_OP_reinterpret` operation. - pub fn reinterpret(self, value_type: ValueType, addr_mask: u64) -> Result<Value> { - if self.value_type().bit_size(addr_mask) != value_type.bit_size(addr_mask) { - return Err(Error::TypeMismatch); - } - let bits = match self { - Value::Generic(value) => value, - Value::I8(value) => value as u64, - Value::U8(value) => u64::from(value), - Value::I16(value) => value as u64, - Value::U16(value) => u64::from(value), - Value::I32(value) => value as u64, - Value::U32(value) => u64::from(value), - Value::I64(value) => value as u64, - Value::U64(value) => value, - Value::F32(value) => u64::from(f32::to_bits(value)), - Value::F64(value) => f64::to_bits(value), - }; - let value = match value_type { - ValueType::Generic => Value::Generic(bits), - ValueType::I8 => Value::I8(bits as i8), - ValueType::U8 => Value::U8(bits as u8), - ValueType::I16 => Value::I16(bits as i16), - ValueType::U16 => Value::U16(bits as u16), - ValueType::I32 => Value::I32(bits as i32), - ValueType::U32 => Value::U32(bits as u32), - ValueType::I64 => Value::I64(bits as i64), - ValueType::U64 => Value::U64(bits), - ValueType::F32 => Value::F32(f32::from_bits(bits as u32)), - ValueType::F64 => Value::F64(f64::from_bits(bits)), - }; - Ok(value) - } - - /// Perform an absolute value operation. - /// - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_abs` operation. - pub fn abs(self, addr_mask: u64) -> Result<Value> { - // wrapping_abs() can be used because DWARF specifies that the result is undefined - // for negative minimal values. - let value = match self { - Value::Generic(value) => { - Value::Generic(sign_extend(value, addr_mask).wrapping_abs() as u64) - } - Value::I8(value) => Value::I8(value.wrapping_abs()), - Value::I16(value) => Value::I16(value.wrapping_abs()), - Value::I32(value) => Value::I32(value.wrapping_abs()), - Value::I64(value) => Value::I64(value.wrapping_abs()), - // f32/f64::abs() is not available in libcore - Value::F32(value) => Value::F32(if value < 0. { -value } else { value }), - Value::F64(value) => Value::F64(if value < 0. { -value } else { value }), - Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => self, - }; - Ok(value) - } - - /// Perform a negation operation. - /// - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_neg` operation. - pub fn neg(self, addr_mask: u64) -> Result<Value> { - // wrapping_neg() can be used because DWARF specifies that the result is undefined - // for negative minimal values. - let value = match self { - Value::Generic(value) => { - Value::Generic(sign_extend(value, addr_mask).wrapping_neg() as u64) - } - Value::I8(value) => Value::I8(value.wrapping_neg()), - Value::I16(value) => Value::I16(value.wrapping_neg()), - Value::I32(value) => Value::I32(value.wrapping_neg()), - Value::I64(value) => Value::I64(value.wrapping_neg()), - Value::F32(value) => Value::F32(-value), - Value::F64(value) => Value::F64(-value), - // It's unclear if these should implicitly convert to a signed value. - // For now, we don't support them. - Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => { - return Err(Error::UnsupportedTypeOperation); - } - }; - Ok(value) - } - - /// Perform an addition operation. - /// - /// This operation requires matching types. - /// - /// This corresponds to the DWARF `DW_OP_plus` operation. - pub fn add(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - Value::Generic(v1.wrapping_add(v2) & addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_add(v2)), - (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_add(v2)), - (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_add(v2)), - (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_add(v2)), - (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_add(v2)), - (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_add(v2)), - (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_add(v2)), - (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_add(v2)), - (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 + v2), - (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 + v2), - _ => return Err(Error::TypeMismatch), - }; - Ok(value) - } - - /// Perform a subtraction operation. - /// - /// This operation requires matching types. - /// - /// This corresponds to the DWARF `DW_OP_minus` operation. - pub fn sub(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - Value::Generic(v1.wrapping_sub(v2) & addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_sub(v2)), - (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_sub(v2)), - (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_sub(v2)), - (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_sub(v2)), - (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_sub(v2)), - (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_sub(v2)), - (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_sub(v2)), - (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_sub(v2)), - (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 - v2), - (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 - v2), - _ => return Err(Error::TypeMismatch), - }; - Ok(value) - } - - /// Perform a multiplication operation. - /// - /// This operation requires matching types. - /// - /// This corresponds to the DWARF `DW_OP_mul` operation. - pub fn mul(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - Value::Generic(v1.wrapping_mul(v2) & addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_mul(v2)), - (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_mul(v2)), - (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_mul(v2)), - (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_mul(v2)), - (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_mul(v2)), - (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_mul(v2)), - (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_mul(v2)), - (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_mul(v2)), - (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 * v2), - (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 * v2), - _ => return Err(Error::TypeMismatch), - }; - Ok(value) - } - - /// Perform a division operation. - /// - /// This operation requires matching types. - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_div` operation. - pub fn div(self, rhs: Value, addr_mask: u64) -> Result<Value> { - match rhs { - Value::Generic(v2) if sign_extend(v2, addr_mask) == 0 => { - return Err(Error::DivisionByZero); - } - Value::I8(0) - | Value::U8(0) - | Value::I16(0) - | Value::U16(0) - | Value::I32(0) - | Value::U32(0) - | Value::I64(0) - | Value::U64(0) => { - return Err(Error::DivisionByZero); - } - _ => {} - } - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - // Signed division - Value::Generic( - sign_extend(v1, addr_mask).wrapping_div(sign_extend(v2, addr_mask)) as u64, - ) - } - (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_div(v2)), - (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_div(v2)), - (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_div(v2)), - (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_div(v2)), - (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_div(v2)), - (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_div(v2)), - (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_div(v2)), - (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_div(v2)), - (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 / v2), - (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 / v2), - _ => return Err(Error::TypeMismatch), - }; - Ok(value) - } - - /// Perform a remainder operation. - /// - /// This operation requires matching integral types. - /// If the value type is `Generic`, then it is interpreted as an unsigned value. - /// - /// This corresponds to the DWARF `DW_OP_mod` operation. - pub fn rem(self, rhs: Value, addr_mask: u64) -> Result<Value> { - match rhs { - Value::Generic(rhs) if (rhs & addr_mask) == 0 => { - return Err(Error::DivisionByZero); - } - Value::I8(0) - | Value::U8(0) - | Value::I16(0) - | Value::U16(0) - | Value::I32(0) - | Value::U32(0) - | Value::I64(0) - | Value::U64(0) => { - return Err(Error::DivisionByZero); - } - _ => {} - } - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - // Unsigned modulus - Value::Generic((v1 & addr_mask).wrapping_rem(v2 & addr_mask)) - } - (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_rem(v2)), - (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_rem(v2)), - (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_rem(v2)), - (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_rem(v2)), - (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_rem(v2)), - (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_rem(v2)), - (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_rem(v2)), - (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_rem(v2)), - (Value::F32(_), Value::F32(_)) => return Err(Error::IntegralTypeRequired), - (Value::F64(_), Value::F64(_)) => return Err(Error::IntegralTypeRequired), - _ => return Err(Error::TypeMismatch), - }; - Ok(value) - } - - /// Perform a bitwise not operation. - /// - /// This operation requires matching integral types. - /// - /// This corresponds to the DWARF `DW_OP_not` operation. - pub fn not(self, addr_mask: u64) -> Result<Value> { - let value_type = self.value_type(); - let v = self.to_u64(addr_mask)?; - Value::from_u64(value_type, !v) - } - - /// Perform a bitwise and operation. - /// - /// This operation requires matching integral types. - /// - /// This corresponds to the DWARF `DW_OP_and` operation. - pub fn and(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value_type = self.value_type(); - if value_type != rhs.value_type() { - return Err(Error::TypeMismatch); - } - let v1 = self.to_u64(addr_mask)?; - let v2 = rhs.to_u64(addr_mask)?; - Value::from_u64(value_type, v1 & v2) - } - - /// Perform a bitwise or operation. - /// - /// This operation requires matching integral types. - /// - /// This corresponds to the DWARF `DW_OP_or` operation. - pub fn or(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value_type = self.value_type(); - if value_type != rhs.value_type() { - return Err(Error::TypeMismatch); - } - let v1 = self.to_u64(addr_mask)?; - let v2 = rhs.to_u64(addr_mask)?; - Value::from_u64(value_type, v1 | v2) - } - - /// Perform a bitwise exclusive-or operation. - /// - /// This operation requires matching integral types. - /// - /// This corresponds to the DWARF `DW_OP_xor` operation. - pub fn xor(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value_type = self.value_type(); - if value_type != rhs.value_type() { - return Err(Error::TypeMismatch); - } - let v1 = self.to_u64(addr_mask)?; - let v2 = rhs.to_u64(addr_mask)?; - Value::from_u64(value_type, v1 ^ v2) - } - - /// Convert value to bit length suitable for a shift operation. - /// - /// If the value is negative then an error is returned. - fn shift_length(self) -> Result<u64> { - let value = match self { - Value::Generic(value) => value, - Value::I8(value) if value >= 0 => value as u64, - Value::U8(value) => u64::from(value), - Value::I16(value) if value >= 0 => value as u64, - Value::U16(value) => u64::from(value), - Value::I32(value) if value >= 0 => value as u64, - Value::U32(value) => u64::from(value), - Value::I64(value) if value >= 0 => value as u64, - Value::U64(value) => value, - _ => return Err(Error::InvalidShiftExpression), - }; - Ok(value) - } - - /// Perform a shift left operation. - /// - /// This operation requires integral types. - /// If the shift length exceeds the type size, then 0 is returned. - /// If the shift length is negative then an error is returned. - /// - /// This corresponds to the DWARF `DW_OP_shl` operation. - pub fn shl(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let v2 = rhs.shift_length()?; - let value = match self { - Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) { - 0 - } else { - (v1 & addr_mask) << v2 - }), - Value::I8(v1) => Value::I8(if v2 >= 8 { 0 } else { v1 << v2 }), - Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 << v2 }), - Value::I16(v1) => Value::I16(if v2 >= 16 { 0 } else { v1 << v2 }), - Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 << v2 }), - Value::I32(v1) => Value::I32(if v2 >= 32 { 0 } else { v1 << v2 }), - Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 << v2 }), - Value::I64(v1) => Value::I64(if v2 >= 64 { 0 } else { v1 << v2 }), - Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 << v2 }), - _ => return Err(Error::IntegralTypeRequired), - }; - Ok(value) - } - - /// Perform a logical shift right operation. - /// - /// This operation requires an unsigned integral type for the value. - /// If the value type is `Generic`, then it is interpreted as an unsigned value. - /// - /// This operation requires an integral type for the shift length. - /// If the shift length exceeds the type size, then 0 is returned. - /// If the shift length is negative then an error is returned. - /// - /// This corresponds to the DWARF `DW_OP_shr` operation. - pub fn shr(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let v2 = rhs.shift_length()?; - let value = match self { - Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) { - 0 - } else { - (v1 & addr_mask) >> v2 - }), - Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 >> v2 }), - Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 >> v2 }), - Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 >> v2 }), - Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 >> v2 }), - // It's unclear if signed values should implicitly convert to an unsigned value. - // For now, we don't support them. - Value::I8(_) | Value::I16(_) | Value::I32(_) | Value::I64(_) => { - return Err(Error::UnsupportedTypeOperation); - } - _ => return Err(Error::IntegralTypeRequired), - }; - Ok(value) - } - - /// Perform an arithmetic shift right operation. - /// - /// This operation requires a signed integral type for the value. - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This operation requires an integral type for the shift length. - /// If the shift length exceeds the type size, then 0 is returned for positive values, - /// and -1 is returned for negative values. - /// If the shift length is negative then an error is returned. - /// - /// This corresponds to the DWARF `DW_OP_shra` operation. - pub fn shra(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let v2 = rhs.shift_length()?; - let value = match self { - Value::Generic(v1) => { - let v1 = sign_extend(v1, addr_mask); - let value = if v2 >= u64::from(mask_bit_size(addr_mask)) { - if v1 < 0 { - !0 - } else { - 0 - } - } else { - (v1 >> v2) as u64 - }; - Value::Generic(value) - } - Value::I8(v1) => Value::I8(if v2 >= 8 { - if v1 < 0 { - !0 - } else { - 0 - } - } else { - v1 >> v2 - }), - Value::I16(v1) => Value::I16(if v2 >= 16 { - if v1 < 0 { - !0 - } else { - 0 - } - } else { - v1 >> v2 - }), - Value::I32(v1) => Value::I32(if v2 >= 32 { - if v1 < 0 { - !0 - } else { - 0 - } - } else { - v1 >> v2 - }), - Value::I64(v1) => Value::I64(if v2 >= 64 { - if v1 < 0 { - !0 - } else { - 0 - } - } else { - v1 >> v2 - }), - // It's unclear if unsigned values should implicitly convert to a signed value. - // For now, we don't support them. - Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => { - return Err(Error::UnsupportedTypeOperation); - } - _ => return Err(Error::IntegralTypeRequired), - }; - Ok(value) - } - - /// Perform the `==` relational operation. - /// - /// This operation requires matching integral types. - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_eq` operation. - pub fn eq(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - sign_extend(v1, addr_mask) == sign_extend(v2, addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => v1 == v2, - (Value::U8(v1), Value::U8(v2)) => v1 == v2, - (Value::I16(v1), Value::I16(v2)) => v1 == v2, - (Value::U16(v1), Value::U16(v2)) => v1 == v2, - (Value::I32(v1), Value::I32(v2)) => v1 == v2, - (Value::U32(v1), Value::U32(v2)) => v1 == v2, - (Value::I64(v1), Value::I64(v2)) => v1 == v2, - (Value::U64(v1), Value::U64(v2)) => v1 == v2, - (Value::F32(v1), Value::F32(v2)) => v1 == v2, - (Value::F64(v1), Value::F64(v2)) => v1 == v2, - _ => return Err(Error::TypeMismatch), - }; - Ok(Value::Generic(value as u64)) - } - - /// Perform the `>=` relational operation. - /// - /// This operation requires matching integral types. - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_ge` operation. - pub fn ge(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - sign_extend(v1, addr_mask) >= sign_extend(v2, addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => v1 >= v2, - (Value::U8(v1), Value::U8(v2)) => v1 >= v2, - (Value::I16(v1), Value::I16(v2)) => v1 >= v2, - (Value::U16(v1), Value::U16(v2)) => v1 >= v2, - (Value::I32(v1), Value::I32(v2)) => v1 >= v2, - (Value::U32(v1), Value::U32(v2)) => v1 >= v2, - (Value::I64(v1), Value::I64(v2)) => v1 >= v2, - (Value::U64(v1), Value::U64(v2)) => v1 >= v2, - (Value::F32(v1), Value::F32(v2)) => v1 >= v2, - (Value::F64(v1), Value::F64(v2)) => v1 >= v2, - _ => return Err(Error::TypeMismatch), - }; - Ok(Value::Generic(value as u64)) - } - - /// Perform the `>` relational operation. - /// - /// This operation requires matching integral types. - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_gt` operation. - pub fn gt(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - sign_extend(v1, addr_mask) > sign_extend(v2, addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => v1 > v2, - (Value::U8(v1), Value::U8(v2)) => v1 > v2, - (Value::I16(v1), Value::I16(v2)) => v1 > v2, - (Value::U16(v1), Value::U16(v2)) => v1 > v2, - (Value::I32(v1), Value::I32(v2)) => v1 > v2, - (Value::U32(v1), Value::U32(v2)) => v1 > v2, - (Value::I64(v1), Value::I64(v2)) => v1 > v2, - (Value::U64(v1), Value::U64(v2)) => v1 > v2, - (Value::F32(v1), Value::F32(v2)) => v1 > v2, - (Value::F64(v1), Value::F64(v2)) => v1 > v2, - _ => return Err(Error::TypeMismatch), - }; - Ok(Value::Generic(value as u64)) - } - - /// Perform the `<= relational operation. - /// - /// This operation requires matching integral types. - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_le` operation. - pub fn le(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - sign_extend(v1, addr_mask) <= sign_extend(v2, addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => v1 <= v2, - (Value::U8(v1), Value::U8(v2)) => v1 <= v2, - (Value::I16(v1), Value::I16(v2)) => v1 <= v2, - (Value::U16(v1), Value::U16(v2)) => v1 <= v2, - (Value::I32(v1), Value::I32(v2)) => v1 <= v2, - (Value::U32(v1), Value::U32(v2)) => v1 <= v2, - (Value::I64(v1), Value::I64(v2)) => v1 <= v2, - (Value::U64(v1), Value::U64(v2)) => v1 <= v2, - (Value::F32(v1), Value::F32(v2)) => v1 <= v2, - (Value::F64(v1), Value::F64(v2)) => v1 <= v2, - _ => return Err(Error::TypeMismatch), - }; - Ok(Value::Generic(value as u64)) - } - - /// Perform the `< relational operation. - /// - /// This operation requires matching integral types. - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_lt` operation. - pub fn lt(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - sign_extend(v1, addr_mask) < sign_extend(v2, addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => v1 < v2, - (Value::U8(v1), Value::U8(v2)) => v1 < v2, - (Value::I16(v1), Value::I16(v2)) => v1 < v2, - (Value::U16(v1), Value::U16(v2)) => v1 < v2, - (Value::I32(v1), Value::I32(v2)) => v1 < v2, - (Value::U32(v1), Value::U32(v2)) => v1 < v2, - (Value::I64(v1), Value::I64(v2)) => v1 < v2, - (Value::U64(v1), Value::U64(v2)) => v1 < v2, - (Value::F32(v1), Value::F32(v2)) => v1 < v2, - (Value::F64(v1), Value::F64(v2)) => v1 < v2, - _ => return Err(Error::TypeMismatch), - }; - Ok(Value::Generic(value as u64)) - } - - /// Perform the `!= relational operation. - /// - /// This operation requires matching integral types. - /// If the value type is `Generic`, then it is interpreted as a signed value. - /// - /// This corresponds to the DWARF `DW_OP_ne` operation. - pub fn ne(self, rhs: Value, addr_mask: u64) -> Result<Value> { - let value = match (self, rhs) { - (Value::Generic(v1), Value::Generic(v2)) => { - sign_extend(v1, addr_mask) != sign_extend(v2, addr_mask) - } - (Value::I8(v1), Value::I8(v2)) => v1 != v2, - (Value::U8(v1), Value::U8(v2)) => v1 != v2, - (Value::I16(v1), Value::I16(v2)) => v1 != v2, - (Value::U16(v1), Value::U16(v2)) => v1 != v2, - (Value::I32(v1), Value::I32(v2)) => v1 != v2, - (Value::U32(v1), Value::U32(v2)) => v1 != v2, - (Value::I64(v1), Value::I64(v2)) => v1 != v2, - (Value::U64(v1), Value::U64(v2)) => v1 != v2, - (Value::F32(v1), Value::F32(v2)) => v1 != v2, - (Value::F64(v1), Value::F64(v2)) => v1 != v2, - _ => return Err(Error::TypeMismatch), - }; - Ok(Value::Generic(value as u64)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::common::{DebugAbbrevOffset, DebugInfoOffset, Encoding, Format}; - use crate::endianity::LittleEndian; - use crate::read::{ - Abbreviation, AttributeSpecification, DebuggingInformationEntry, EndianSlice, UnitHeader, - UnitOffset, UnitType, - }; - - #[test] - #[rustfmt::skip] - fn valuetype_from_encoding() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 4, - }; - let unit = UnitHeader::new( - encoding, - 7, - UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - EndianSlice::new(&[], LittleEndian), - ); - - let abbrev = Abbreviation::new( - 42, - constants::DW_TAG_base_type, - constants::DW_CHILDREN_no, - vec![ - AttributeSpecification::new( - constants::DW_AT_byte_size, - constants::DW_FORM_udata, - None, - ), - AttributeSpecification::new( - constants::DW_AT_encoding, - constants::DW_FORM_udata, - None, - ), - AttributeSpecification::new( - constants::DW_AT_endianity, - constants::DW_FORM_udata, - None, - ), - ].into(), - ); - - for &(attrs, result) in &[ - ([0x01, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I8), - ([0x02, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I16), - ([0x04, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I32), - ([0x08, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I64), - ([0x01, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U8), - ([0x02, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U16), - ([0x04, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U32), - ([0x08, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U64), - ([0x04, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F32), - ([0x08, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F64), - ] { - let entry = DebuggingInformationEntry::new( - UnitOffset(0), - EndianSlice::new(&attrs, LittleEndian), - &abbrev, - &unit, - ); - assert_eq!(ValueType::from_entry(&entry), Ok(Some(result))); - } - - for attrs in &[ - [0x03, constants::DW_ATE_signed.0, constants::DW_END_default.0], - [0x02, constants::DW_ATE_signed.0, constants::DW_END_big.0], - ] { - let entry = DebuggingInformationEntry::new( - UnitOffset(0), - EndianSlice::new(attrs, LittleEndian), - &abbrev, - &unit, - ); - assert_eq!(ValueType::from_entry(&entry), Ok(None)); - } - } - - #[test] - fn value_convert() { - let addr_mask = !0 >> 32; - for &(v, t, result) in &[ - (Value::Generic(1), ValueType::I8, Ok(Value::I8(1))), - (Value::I8(1), ValueType::U8, Ok(Value::U8(1))), - (Value::U8(1), ValueType::I16, Ok(Value::I16(1))), - (Value::I16(1), ValueType::U16, Ok(Value::U16(1))), - (Value::U16(1), ValueType::I32, Ok(Value::I32(1))), - (Value::I32(1), ValueType::U32, Ok(Value::U32(1))), - (Value::U32(1), ValueType::F32, Ok(Value::F32(1.))), - (Value::F32(1.), ValueType::I64, Ok(Value::I64(1))), - (Value::I64(1), ValueType::U64, Ok(Value::U64(1))), - (Value::U64(1), ValueType::F64, Ok(Value::F64(1.))), - (Value::F64(1.), ValueType::Generic, Ok(Value::Generic(1))), - ] { - assert_eq!(v.convert(t, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_reinterpret() { - let addr_mask = !0 >> 32; - for &(v, t, result) in &[ - // 8-bit - (Value::I8(-1), ValueType::U8, Ok(Value::U8(0xff))), - (Value::U8(0xff), ValueType::I8, Ok(Value::I8(-1))), - // 16-bit - (Value::I16(1), ValueType::U16, Ok(Value::U16(1))), - (Value::U16(1), ValueType::I16, Ok(Value::I16(1))), - // 32-bit - (Value::Generic(1), ValueType::I32, Ok(Value::I32(1))), - (Value::I32(1), ValueType::U32, Ok(Value::U32(1))), - (Value::U32(0x3f80_0000), ValueType::F32, Ok(Value::F32(1.0))), - (Value::F32(1.0), ValueType::Generic, Ok(Value::Generic(0x3f80_0000))), - // Type mismatches - (Value::Generic(1), ValueType::U8, Err(Error::TypeMismatch)), - (Value::U8(1), ValueType::U16, Err(Error::TypeMismatch)), - (Value::U16(1), ValueType::U32, Err(Error::TypeMismatch)), - (Value::U32(1), ValueType::U64, Err(Error::TypeMismatch)), - (Value::U64(1), ValueType::Generic, Err(Error::TypeMismatch)), - ] { - assert_eq!(v.reinterpret(t, addr_mask), result); - } - - let addr_mask = !0; - for &(v, t, result) in &[ - // 64-bit - (Value::Generic(1), ValueType::I64, Ok(Value::I64(1))), - (Value::I64(1), ValueType::U64, Ok(Value::U64(1))), - (Value::U64(0x3ff0_0000_0000_0000), ValueType::F64, Ok(Value::F64(1.0))), - (Value::F64(1.0), ValueType::Generic, Ok(Value::Generic(0x3ff0_0000_0000_0000))), - ] { - assert_eq!(v.reinterpret(t, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_abs() { - let addr_mask = 0xffff_ffff; - for &(v, result) in &[ - (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))), - (Value::I8(-1), Ok(Value::I8(1))), - (Value::U8(1), Ok(Value::U8(1))), - (Value::I16(-1), Ok(Value::I16(1))), - (Value::U16(1), Ok(Value::U16(1))), - (Value::I32(-1), Ok(Value::I32(1))), - (Value::U32(1), Ok(Value::U32(1))), - (Value::I64(-1), Ok(Value::I64(1))), - (Value::U64(1), Ok(Value::U64(1))), - (Value::F32(-1.), Ok(Value::F32(1.))), - (Value::F64(-1.), Ok(Value::F64(1.))), - ] { - assert_eq!(v.abs(addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_neg() { - let addr_mask = 0xffff_ffff; - for &(v, result) in &[ - (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))), - (Value::I8(1), Ok(Value::I8(-1))), - (Value::U8(1), Err(Error::UnsupportedTypeOperation)), - (Value::I16(1), Ok(Value::I16(-1))), - (Value::U16(1), Err(Error::UnsupportedTypeOperation)), - (Value::I32(1), Ok(Value::I32(-1))), - (Value::U32(1), Err(Error::UnsupportedTypeOperation)), - (Value::I64(1), Ok(Value::I64(-1))), - (Value::U64(1), Err(Error::UnsupportedTypeOperation)), - (Value::F32(1.), Ok(Value::F32(-1.))), - (Value::F64(1.), Ok(Value::F64(-1.))), - ] { - assert_eq!(v.neg(addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_add() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(1), Value::Generic(2), Ok(Value::Generic(3))), - (Value::I8(-1), Value::I8(2), Ok(Value::I8(1))), - (Value::U8(1), Value::U8(2), Ok(Value::U8(3))), - (Value::I16(-1), Value::I16(2), Ok(Value::I16(1))), - (Value::U16(1), Value::U16(2), Ok(Value::U16(3))), - (Value::I32(-1), Value::I32(2), Ok(Value::I32(1))), - (Value::U32(1), Value::U32(2), Ok(Value::U32(3))), - (Value::I64(-1), Value::I64(2), Ok(Value::I64(1))), - (Value::U64(1), Value::U64(2), Ok(Value::U64(3))), - (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(1.))), - (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(1.))), - (Value::Generic(1), Value::U32(2), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.add(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_sub() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))), - (Value::I8(-1), Value::I8(2), Ok(Value::I8(-3))), - (Value::U8(3), Value::U8(2), Ok(Value::U8(1))), - (Value::I16(-1), Value::I16(2), Ok(Value::I16(-3))), - (Value::U16(3), Value::U16(2), Ok(Value::U16(1))), - (Value::I32(-1), Value::I32(2), Ok(Value::I32(-3))), - (Value::U32(3), Value::U32(2), Ok(Value::U32(1))), - (Value::I64(-1), Value::I64(2), Ok(Value::I64(-3))), - (Value::U64(3), Value::U64(2), Ok(Value::U64(1))), - (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(-3.))), - (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(-3.))), - (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.sub(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_mul() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(2), Value::Generic(3), Ok(Value::Generic(6))), - (Value::I8(-2), Value::I8(3), Ok(Value::I8(-6))), - (Value::U8(2), Value::U8(3), Ok(Value::U8(6))), - (Value::I16(-2), Value::I16(3), Ok(Value::I16(-6))), - (Value::U16(2), Value::U16(3), Ok(Value::U16(6))), - (Value::I32(-2), Value::I32(3), Ok(Value::I32(-6))), - (Value::U32(2), Value::U32(3), Ok(Value::U32(6))), - (Value::I64(-2), Value::I64(3), Ok(Value::I64(-6))), - (Value::U64(2), Value::U64(3), Ok(Value::U64(6))), - (Value::F32(-2.), Value::F32(3.), Ok(Value::F32(-6.))), - (Value::F64(-2.), Value::F64(3.), Ok(Value::F64(-6.))), - (Value::Generic(2), Value::U32(3), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.mul(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_div() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(6), Value::Generic(3), Ok(Value::Generic(2))), - (Value::I8(-6), Value::I8(3), Ok(Value::I8(-2))), - (Value::U8(6), Value::U8(3), Ok(Value::U8(2))), - (Value::I16(-6), Value::I16(3), Ok(Value::I16(-2))), - (Value::U16(6), Value::U16(3), Ok(Value::U16(2))), - (Value::I32(-6), Value::I32(3), Ok(Value::I32(-2))), - (Value::U32(6), Value::U32(3), Ok(Value::U32(2))), - (Value::I64(-6), Value::I64(3), Ok(Value::I64(-2))), - (Value::U64(6), Value::U64(3), Ok(Value::U64(2))), - (Value::F32(-6.), Value::F32(3.), Ok(Value::F32(-2.))), - (Value::F64(-6.), Value::F64(3.), Ok(Value::F64(-2.))), - (Value::Generic(6), Value::U32(3), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.div(v2, addr_mask), result); - } - for &(v1, v2, result) in &[ - (Value::Generic(6), Value::Generic(0), Err(Error::DivisionByZero)), - (Value::I8(-6), Value::I8(0), Err(Error::DivisionByZero)), - (Value::U8(6), Value::U8(0), Err(Error::DivisionByZero)), - (Value::I16(-6), Value::I16(0), Err(Error::DivisionByZero)), - (Value::U16(6), Value::U16(0), Err(Error::DivisionByZero)), - (Value::I32(-6), Value::I32(0), Err(Error::DivisionByZero)), - (Value::U32(6), Value::U32(0), Err(Error::DivisionByZero)), - (Value::I64(-6), Value::I64(0), Err(Error::DivisionByZero)), - (Value::U64(6), Value::U64(0), Err(Error::DivisionByZero)), - (Value::F32(-6.), Value::F32(0.), Ok(Value::F32(-6. / 0.))), - (Value::F64(-6.), Value::F64(0.), Ok(Value::F64(-6. / 0.))), - ] { - assert_eq!(v1.div(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_rem() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))), - (Value::I8(-3), Value::I8(2), Ok(Value::I8(-1))), - (Value::U8(3), Value::U8(2), Ok(Value::U8(1))), - (Value::I16(-3), Value::I16(2), Ok(Value::I16(-1))), - (Value::U16(3), Value::U16(2), Ok(Value::U16(1))), - (Value::I32(-3), Value::I32(2), Ok(Value::I32(-1))), - (Value::U32(3), Value::U32(2), Ok(Value::U32(1))), - (Value::I64(-3), Value::I64(2), Ok(Value::I64(-1))), - (Value::U64(3), Value::U64(2), Ok(Value::U64(1))), - (Value::F32(-3.), Value::F32(2.), Err(Error::IntegralTypeRequired)), - (Value::F64(-3.), Value::F64(2.), Err(Error::IntegralTypeRequired)), - (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.rem(v2, addr_mask), result); - } - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(0), Err(Error::DivisionByZero)), - (Value::I8(-3), Value::I8(0), Err(Error::DivisionByZero)), - (Value::U8(3), Value::U8(0), Err(Error::DivisionByZero)), - (Value::I16(-3), Value::I16(0), Err(Error::DivisionByZero)), - (Value::U16(3), Value::U16(0), Err(Error::DivisionByZero)), - (Value::I32(-3), Value::I32(0), Err(Error::DivisionByZero)), - (Value::U32(3), Value::U32(0), Err(Error::DivisionByZero)), - (Value::I64(-3), Value::I64(0), Err(Error::DivisionByZero)), - (Value::U64(3), Value::U64(0), Err(Error::DivisionByZero)), - ] { - assert_eq!(v1.rem(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_not() { - let addr_mask = 0xffff_ffff; - for &(v, result) in &[ - (Value::Generic(1), Ok(Value::Generic(!1))), - (Value::I8(1), Ok(Value::I8(!1))), - (Value::U8(1), Ok(Value::U8(!1))), - (Value::I16(1), Ok(Value::I16(!1))), - (Value::U16(1), Ok(Value::U16(!1))), - (Value::I32(1), Ok(Value::I32(!1))), - (Value::U32(1), Ok(Value::U32(!1))), - (Value::I64(1), Ok(Value::I64(!1))), - (Value::U64(1), Ok(Value::U64(!1))), - (Value::F32(1.), Err(Error::IntegralTypeRequired)), - (Value::F64(1.), Err(Error::IntegralTypeRequired)), - ] { - assert_eq!(v.not(addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_and() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(1))), - (Value::I8(3), Value::I8(5), Ok(Value::I8(1))), - (Value::U8(3), Value::U8(5), Ok(Value::U8(1))), - (Value::I16(3), Value::I16(5), Ok(Value::I16(1))), - (Value::U16(3), Value::U16(5), Ok(Value::U16(1))), - (Value::I32(3), Value::I32(5), Ok(Value::I32(1))), - (Value::U32(3), Value::U32(5), Ok(Value::U32(1))), - (Value::I64(3), Value::I64(5), Ok(Value::I64(1))), - (Value::U64(3), Value::U64(5), Ok(Value::U64(1))), - (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), - (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), - (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.and(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_or() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(7))), - (Value::I8(3), Value::I8(5), Ok(Value::I8(7))), - (Value::U8(3), Value::U8(5), Ok(Value::U8(7))), - (Value::I16(3), Value::I16(5), Ok(Value::I16(7))), - (Value::U16(3), Value::U16(5), Ok(Value::U16(7))), - (Value::I32(3), Value::I32(5), Ok(Value::I32(7))), - (Value::U32(3), Value::U32(5), Ok(Value::U32(7))), - (Value::I64(3), Value::I64(5), Ok(Value::I64(7))), - (Value::U64(3), Value::U64(5), Ok(Value::U64(7))), - (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), - (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), - (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.or(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_xor() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(6))), - (Value::I8(3), Value::I8(5), Ok(Value::I8(6))), - (Value::U8(3), Value::U8(5), Ok(Value::U8(6))), - (Value::I16(3), Value::I16(5), Ok(Value::I16(6))), - (Value::U16(3), Value::U16(5), Ok(Value::U16(6))), - (Value::I32(3), Value::I32(5), Ok(Value::I32(6))), - (Value::U32(3), Value::U32(5), Ok(Value::U32(6))), - (Value::I64(3), Value::I64(5), Ok(Value::I64(6))), - (Value::U64(3), Value::U64(5), Ok(Value::U64(6))), - (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), - (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), - (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.xor(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_shl() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - // One of each type - (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(96))), - (Value::I8(3), Value::U8(5), Ok(Value::I8(96))), - (Value::U8(3), Value::I8(5), Ok(Value::U8(96))), - (Value::I16(3), Value::U16(5), Ok(Value::I16(96))), - (Value::U16(3), Value::I16(5), Ok(Value::U16(96))), - (Value::I32(3), Value::U32(5), Ok(Value::I32(96))), - (Value::U32(3), Value::I32(5), Ok(Value::U32(96))), - (Value::I64(3), Value::U64(5), Ok(Value::I64(96))), - (Value::U64(3), Value::I64(5), Ok(Value::U64(96))), - (Value::F32(3.), Value::U8(5), Err(Error::IntegralTypeRequired)), - (Value::F64(3.), Value::U8(5), Err(Error::IntegralTypeRequired)), - // Invalid shifts - (Value::U8(3), Value::I8(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(3), Value::I16(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(3), Value::I32(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(3), Value::I64(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(3), Value::F32(5.), Err(Error::InvalidShiftExpression)), - (Value::U8(3), Value::F64(5.), Err(Error::InvalidShiftExpression)), - // Large shifts - (Value::Generic(3), Value::Generic(32), Ok(Value::Generic(0))), - (Value::I8(3), Value::U8(8), Ok(Value::I8(0))), - (Value::U8(3), Value::I8(9), Ok(Value::U8(0))), - (Value::I16(3), Value::U16(17), Ok(Value::I16(0))), - (Value::U16(3), Value::I16(16), Ok(Value::U16(0))), - (Value::I32(3), Value::U32(32), Ok(Value::I32(0))), - (Value::U32(3), Value::I32(33), Ok(Value::U32(0))), - (Value::I64(3), Value::U64(65), Ok(Value::I64(0))), - (Value::U64(3), Value::I64(64), Ok(Value::U64(0))), - ] { - assert_eq!(v1.shl(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_shr() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - // One of each type - (Value::Generic(96), Value::Generic(5), Ok(Value::Generic(3))), - (Value::I8(96), Value::U8(5), Err(Error::UnsupportedTypeOperation)), - (Value::U8(96), Value::I8(5), Ok(Value::U8(3))), - (Value::I16(96), Value::U16(5), Err(Error::UnsupportedTypeOperation)), - (Value::U16(96), Value::I16(5), Ok(Value::U16(3))), - (Value::I32(96), Value::U32(5), Err(Error::UnsupportedTypeOperation)), - (Value::U32(96), Value::I32(5), Ok(Value::U32(3))), - (Value::I64(96), Value::U64(5), Err(Error::UnsupportedTypeOperation)), - (Value::U64(96), Value::I64(5), Ok(Value::U64(3))), - (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), - (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), - // Invalid shifts - (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)), - // Large shifts - (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))), - (Value::U8(96), Value::I8(9), Ok(Value::U8(0))), - (Value::U16(96), Value::I16(16), Ok(Value::U16(0))), - (Value::U32(96), Value::I32(33), Ok(Value::U32(0))), - (Value::U64(96), Value::I64(64), Ok(Value::U64(0))), - ] { - assert_eq!(v1.shr(v2, addr_mask), result); - } - } - - #[test] - #[rustfmt::skip] - fn value_shra() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - // One of each type - (Value::Generic(u64::from(-96i32 as u32)), Value::Generic(5), Ok(Value::Generic(-3i64 as u64))), - (Value::I8(-96), Value::U8(5), Ok(Value::I8(-3))), - (Value::U8(96), Value::I8(5), Err(Error::UnsupportedTypeOperation)), - (Value::I16(-96), Value::U16(5), Ok(Value::I16(-3))), - (Value::U16(96), Value::I16(5), Err(Error::UnsupportedTypeOperation)), - (Value::I32(-96), Value::U32(5), Ok(Value::I32(-3))), - (Value::U32(96), Value::I32(5), Err(Error::UnsupportedTypeOperation)), - (Value::I64(-96), Value::U64(5), Ok(Value::I64(-3))), - (Value::U64(96), Value::I64(5), Err(Error::UnsupportedTypeOperation)), - (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), - (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), - // Invalid shifts - (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)), - (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)), - // Large shifts - (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))), - (Value::I8(96), Value::U8(8), Ok(Value::I8(0))), - (Value::I8(-96), Value::U8(8), Ok(Value::I8(-1))), - (Value::I16(96), Value::U16(17), Ok(Value::I16(0))), - (Value::I16(-96), Value::U16(17), Ok(Value::I16(-1))), - (Value::I32(96), Value::U32(32), Ok(Value::I32(0))), - (Value::I32(-96), Value::U32(32), Ok(Value::I32(-1))), - (Value::I64(96), Value::U64(65), Ok(Value::I64(0))), - (Value::I64(-96), Value::U64(65), Ok(Value::I64(-1))), - ] { - assert_eq!(v1.shra(v2, addr_mask), result); - } - } - - #[test] - fn value_eq() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(1))), - (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), - (Value::I8(3), Value::I8(3), Ok(Value::Generic(1))), - (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), - (Value::U8(3), Value::U8(3), Ok(Value::Generic(1))), - (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), - (Value::I16(3), Value::I16(3), Ok(Value::Generic(1))), - (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), - (Value::U16(3), Value::U16(3), Ok(Value::Generic(1))), - (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), - (Value::I32(3), Value::I32(3), Ok(Value::Generic(1))), - (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), - (Value::U32(3), Value::U32(3), Ok(Value::Generic(1))), - (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), - (Value::I64(3), Value::I64(3), Ok(Value::Generic(1))), - (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), - (Value::U64(3), Value::U64(3), Ok(Value::Generic(1))), - (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), - (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(1))), - (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), - (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(1))), - (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), - (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.eq(v2, addr_mask), result); - } - } - - #[test] - fn value_ne() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(0))), - (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), - (Value::I8(3), Value::I8(3), Ok(Value::Generic(0))), - (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), - (Value::U8(3), Value::U8(3), Ok(Value::Generic(0))), - (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), - (Value::I16(3), Value::I16(3), Ok(Value::Generic(0))), - (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), - (Value::U16(3), Value::U16(3), Ok(Value::Generic(0))), - (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), - (Value::I32(3), Value::I32(3), Ok(Value::Generic(0))), - (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), - (Value::U32(3), Value::U32(3), Ok(Value::Generic(0))), - (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), - (Value::I64(3), Value::I64(3), Ok(Value::Generic(0))), - (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), - (Value::U64(3), Value::U64(3), Ok(Value::Generic(0))), - (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), - (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(0))), - (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), - (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(0))), - (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), - (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.ne(v2, addr_mask), result); - } - } - - #[test] - fn value_ge() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))), - (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), - (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))), - (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), - (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))), - (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), - (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))), - (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), - (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))), - (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), - (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))), - (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), - (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))), - (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), - (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))), - (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), - (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))), - (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), - (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))), - (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), - (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))), - (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), - (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.ge(v2, addr_mask), result); - } - } - - #[test] - fn value_gt() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))), - (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), - (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))), - (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), - (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))), - (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), - (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))), - (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), - (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))), - (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), - (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))), - (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), - (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))), - (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), - (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))), - (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), - (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))), - (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), - (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))), - (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), - (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))), - (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), - (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.gt(v2, addr_mask), result); - } - } - - #[test] - fn value_le() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))), - (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), - (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))), - (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), - (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))), - (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), - (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))), - (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), - (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))), - (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), - (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))), - (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), - (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))), - (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), - (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))), - (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), - (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))), - (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), - (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))), - (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), - (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))), - (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), - (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.le(v2, addr_mask), result); - } - } - - #[test] - fn value_lt() { - let addr_mask = 0xffff_ffff; - for &(v1, v2, result) in &[ - (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))), - (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), - (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))), - (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), - (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))), - (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), - (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))), - (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), - (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))), - (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), - (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))), - (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), - (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))), - (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), - (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))), - (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), - (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))), - (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), - (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))), - (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), - (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))), - (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), - (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), - ] { - assert_eq!(v1.lt(v2, addr_mask), result); - } - } -} diff --git a/vendor/gimli/src/test_util.rs b/vendor/gimli/src/test_util.rs deleted file mode 100644 index 706aaf9..0000000 --- a/vendor/gimli/src/test_util.rs +++ /dev/null @@ -1,53 +0,0 @@ -#![allow(missing_docs)] - -use crate::Format; -use test_assembler::{Label, Section}; - -pub trait GimliSectionMethods { - fn sleb(self, val: i64) -> Self; - fn uleb(self, val: u64) -> Self; - fn initial_length(self, format: Format, length: &Label, start: &Label) -> Self; - fn word(self, size: u8, val: u64) -> Self; - fn word_label(self, size: u8, val: &Label) -> Self; -} - -impl GimliSectionMethods for Section { - fn sleb(mut self, mut val: i64) -> Self { - while val & !0x3f != 0 && val | 0x3f != -1 { - self = self.D8(val as u8 | 0x80); - val >>= 7; - } - self.D8(val as u8 & 0x7f) - } - - fn uleb(mut self, mut val: u64) -> Self { - while val & !0x7f != 0 { - self = self.D8(val as u8 | 0x80); - val >>= 7; - } - self.D8(val as u8) - } - - fn initial_length(self, format: Format, length: &Label, start: &Label) -> Self { - match format { - Format::Dwarf32 => self.D32(length).mark(start), - Format::Dwarf64 => self.D32(0xffff_ffff).D64(length).mark(start), - } - } - - fn word(self, size: u8, val: u64) -> Self { - match size { - 4 => self.D32(val as u32), - 8 => self.D64(val), - _ => panic!("unsupported word size"), - } - } - - fn word_label(self, size: u8, val: &Label) -> Self { - match size { - 4 => self.D32(val), - 8 => self.D64(val), - _ => panic!("unsupported word size"), - } - } -} diff --git a/vendor/gimli/src/write/abbrev.rs b/vendor/gimli/src/write/abbrev.rs deleted file mode 100644 index 7cdfa96..0000000 --- a/vendor/gimli/src/write/abbrev.rs +++ /dev/null @@ -1,188 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{DebugAbbrevOffset, SectionId}; -use crate::constants; -use crate::write::{Result, Section, Writer}; - -/// A table of abbreviations that will be stored in a `.debug_abbrev` section. -// Requirements: -// - values are `Abbreviation` -// - insertion returns an abbreviation code for use in writing a DIE -// - inserting a duplicate returns the code of the existing value -#[derive(Debug, Default)] -pub(crate) struct AbbreviationTable { - abbrevs: IndexSet<Abbreviation>, -} - -impl AbbreviationTable { - /// Add an abbreviation to the table and return its code. - pub fn add(&mut self, abbrev: Abbreviation) -> u64 { - let (code, _) = self.abbrevs.insert_full(abbrev); - // Code must be non-zero - (code + 1) as u64 - } - - /// Write the abbreviation table to the `.debug_abbrev` section. - pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> { - for (code, abbrev) in self.abbrevs.iter().enumerate() { - w.write_uleb128((code + 1) as u64)?; - abbrev.write(w)?; - } - // Null abbreviation code - w.write_u8(0) - } -} - -/// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: -/// its tag type, whether it has children, and its set of attributes. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct Abbreviation { - tag: constants::DwTag, - has_children: bool, - attributes: Vec<AttributeSpecification>, -} - -impl Abbreviation { - /// Construct a new `Abbreviation`. - #[inline] - pub fn new( - tag: constants::DwTag, - has_children: bool, - attributes: Vec<AttributeSpecification>, - ) -> Abbreviation { - Abbreviation { - tag, - has_children, - attributes, - } - } - - /// Write the abbreviation to the `.debug_abbrev` section. - pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> { - w.write_uleb128(self.tag.0.into())?; - w.write_u8(if self.has_children { - constants::DW_CHILDREN_yes.0 - } else { - constants::DW_CHILDREN_no.0 - })?; - for attr in &self.attributes { - attr.write(w)?; - } - // Null name and form - w.write_u8(0)?; - w.write_u8(0) - } -} - -/// The description of an attribute in an abbreviated type. -// TODO: support implicit const -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct AttributeSpecification { - name: constants::DwAt, - form: constants::DwForm, -} - -impl AttributeSpecification { - /// Construct a new `AttributeSpecification`. - #[inline] - pub fn new(name: constants::DwAt, form: constants::DwForm) -> AttributeSpecification { - AttributeSpecification { name, form } - } - - /// Write the attribute specification to the `.debug_abbrev` section. - #[inline] - pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> { - w.write_uleb128(self.name.0.into())?; - w.write_uleb128(self.form.0.into()) - } -} - -define_section!( - DebugAbbrev, - DebugAbbrevOffset, - "A writable `.debug_abbrev` section." -); - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::constants; - use crate::read; - use crate::write::EndianVec; - use crate::LittleEndian; - - #[test] - fn test_abbreviation_table() { - let mut abbrevs = AbbreviationTable::default(); - let abbrev1 = Abbreviation::new( - constants::DW_TAG_subprogram, - false, - vec![AttributeSpecification::new( - constants::DW_AT_name, - constants::DW_FORM_string, - )], - ); - let abbrev2 = Abbreviation::new( - constants::DW_TAG_compile_unit, - true, - vec![ - AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp), - AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2), - ], - ); - let code1 = abbrevs.add(abbrev1.clone()); - assert_eq!(code1, 1); - let code2 = abbrevs.add(abbrev2.clone()); - assert_eq!(code2, 2); - assert_eq!(abbrevs.add(abbrev1.clone()), code1); - assert_eq!(abbrevs.add(abbrev2.clone()), code2); - - let mut debug_abbrev = DebugAbbrev::from(EndianVec::new(LittleEndian)); - let debug_abbrev_offset = debug_abbrev.offset(); - assert_eq!(debug_abbrev_offset, DebugAbbrevOffset(0)); - abbrevs.write(&mut debug_abbrev).unwrap(); - assert_eq!(debug_abbrev.offset(), DebugAbbrevOffset(17)); - - let read_debug_abbrev = read::DebugAbbrev::new(debug_abbrev.slice(), LittleEndian); - let read_abbrevs = read_debug_abbrev - .abbreviations(debug_abbrev_offset) - .unwrap(); - - let read_abbrev1 = read_abbrevs.get(code1).unwrap(); - assert_eq!(abbrev1.tag, read_abbrev1.tag()); - assert_eq!(abbrev1.has_children, read_abbrev1.has_children()); - assert_eq!(abbrev1.attributes.len(), read_abbrev1.attributes().len()); - assert_eq!( - abbrev1.attributes[0].name, - read_abbrev1.attributes()[0].name() - ); - assert_eq!( - abbrev1.attributes[0].form, - read_abbrev1.attributes()[0].form() - ); - - let read_abbrev2 = read_abbrevs.get(code2).unwrap(); - assert_eq!(abbrev2.tag, read_abbrev2.tag()); - assert_eq!(abbrev2.has_children, read_abbrev2.has_children()); - assert_eq!(abbrev2.attributes.len(), read_abbrev2.attributes().len()); - assert_eq!( - abbrev2.attributes[0].name, - read_abbrev2.attributes()[0].name() - ); - assert_eq!( - abbrev2.attributes[0].form, - read_abbrev2.attributes()[0].form() - ); - assert_eq!( - abbrev2.attributes[1].name, - read_abbrev2.attributes()[1].name() - ); - assert_eq!( - abbrev2.attributes[1].form, - read_abbrev2.attributes()[1].form() - ); - } -} diff --git a/vendor/gimli/src/write/cfi.rs b/vendor/gimli/src/write/cfi.rs deleted file mode 100644 index 5e108f1..0000000 --- a/vendor/gimli/src/write/cfi.rs +++ /dev/null @@ -1,1050 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId}; -use crate::constants; -use crate::write::{Address, BaseId, Error, Expression, Result, Section, Writer}; - -define_section!( - DebugFrame, - DebugFrameOffset, - "A writable `.debug_frame` section." -); - -define_section!(EhFrame, EhFrameOffset, "A writable `.eh_frame` section."); - -define_id!(CieId, "An identifier for a CIE in a `FrameTable`."); - -/// A table of frame description entries. -#[derive(Debug, Default)] -pub struct FrameTable { - /// Base id for CIEs. - base_id: BaseId, - /// The common information entries. - cies: IndexSet<CommonInformationEntry>, - /// The frame description entries. - fdes: Vec<(CieId, FrameDescriptionEntry)>, -} - -impl FrameTable { - /// Add a CIE and return its id. - /// - /// If the CIE already exists, then return the id of the existing CIE. - pub fn add_cie(&mut self, cie: CommonInformationEntry) -> CieId { - let (index, _) = self.cies.insert_full(cie); - CieId::new(self.base_id, index) - } - - /// The number of CIEs. - pub fn cie_count(&self) -> usize { - self.cies.len() - } - - /// Add a FDE. - /// - /// Does not check for duplicates. - /// - /// # Panics - /// - /// Panics if the CIE id is invalid. - pub fn add_fde(&mut self, cie: CieId, fde: FrameDescriptionEntry) { - debug_assert_eq!(self.base_id, cie.base_id); - self.fdes.push((cie, fde)); - } - - /// The number of FDEs. - pub fn fde_count(&self) -> usize { - self.fdes.len() - } - - /// Write the frame table entries to the given `.debug_frame` section. - pub fn write_debug_frame<W: Writer>(&self, w: &mut DebugFrame<W>) -> Result<()> { - self.write(&mut w.0, false) - } - - /// Write the frame table entries to the given `.eh_frame` section. - pub fn write_eh_frame<W: Writer>(&self, w: &mut EhFrame<W>) -> Result<()> { - self.write(&mut w.0, true) - } - - fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<()> { - let mut cie_offsets = vec![None; self.cies.len()]; - for (cie_id, fde) in &self.fdes { - let cie_index = cie_id.index; - let cie = self.cies.get_index(cie_index).unwrap(); - let cie_offset = match cie_offsets[cie_index] { - Some(offset) => offset, - None => { - // Only write CIEs as they are referenced. - let offset = cie.write(w, eh_frame)?; - cie_offsets[cie_index] = Some(offset); - offset - } - }; - - fde.write(w, eh_frame, cie_offset, cie)?; - } - // TODO: write length 0 terminator for eh_frame? - Ok(()) - } -} - -/// A common information entry. This contains information that is shared between FDEs. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct CommonInformationEntry { - encoding: Encoding, - - /// A constant that is factored out of code offsets. - /// - /// This should be set to the minimum instruction length. - /// Writing a code offset that is not a multiple of this factor will generate an error. - code_alignment_factor: u8, - - /// A constant that is factored out of data offsets. - /// - /// This should be set to the minimum data alignment for the frame. - /// Writing a data offset that is not a multiple of this factor will generate an error. - data_alignment_factor: i8, - - /// The return address register. This might not correspond to an actual machine register. - return_address_register: Register, - - /// The address of the personality function and its encoding. - pub personality: Option<(constants::DwEhPe, Address)>, - - /// The encoding to use for the LSDA address in FDEs. - /// - /// If set then all FDEs which use this CIE must have a LSDA address. - pub lsda_encoding: Option<constants::DwEhPe>, - - /// The encoding to use for addresses in FDEs. - pub fde_address_encoding: constants::DwEhPe, - - /// True for signal trampolines. - pub signal_trampoline: bool, - - /// The initial instructions upon entry to this function. - instructions: Vec<CallFrameInstruction>, -} - -impl CommonInformationEntry { - /// Create a new common information entry. - /// - /// The encoding version must be a CFI version, not a DWARF version. - pub fn new( - encoding: Encoding, - code_alignment_factor: u8, - data_alignment_factor: i8, - return_address_register: Register, - ) -> Self { - CommonInformationEntry { - encoding, - code_alignment_factor, - data_alignment_factor, - return_address_register, - personality: None, - lsda_encoding: None, - fde_address_encoding: constants::DW_EH_PE_absptr, - signal_trampoline: false, - instructions: Vec::new(), - } - } - - /// Add an initial instruction. - pub fn add_instruction(&mut self, instruction: CallFrameInstruction) { - self.instructions.push(instruction); - } - - fn has_augmentation(&self) -> bool { - self.personality.is_some() - || self.lsda_encoding.is_some() - || self.signal_trampoline - || self.fde_address_encoding != constants::DW_EH_PE_absptr - } - - /// Returns the section offset of the CIE. - fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<usize> { - let encoding = self.encoding; - let offset = w.len(); - - let length_offset = w.write_initial_length(encoding.format)?; - let length_base = w.len(); - - if eh_frame { - w.write_u32(0)?; - } else { - match encoding.format { - Format::Dwarf32 => w.write_u32(0xffff_ffff)?, - Format::Dwarf64 => w.write_u64(0xffff_ffff_ffff_ffff)?, - } - } - - if eh_frame { - if encoding.version != 1 { - return Err(Error::UnsupportedVersion(encoding.version)); - }; - } else { - match encoding.version { - 1 | 3 | 4 => {} - _ => return Err(Error::UnsupportedVersion(encoding.version)), - }; - } - w.write_u8(encoding.version as u8)?; - - let augmentation = self.has_augmentation(); - if augmentation { - w.write_u8(b'z')?; - if self.lsda_encoding.is_some() { - w.write_u8(b'L')?; - } - if self.personality.is_some() { - w.write_u8(b'P')?; - } - if self.fde_address_encoding != constants::DW_EH_PE_absptr { - w.write_u8(b'R')?; - } - if self.signal_trampoline { - w.write_u8(b'S')?; - } - } - w.write_u8(0)?; - - if encoding.version >= 4 { - w.write_u8(encoding.address_size)?; - // TODO: segment_selector_size - w.write_u8(0)?; - } - - w.write_uleb128(self.code_alignment_factor.into())?; - w.write_sleb128(self.data_alignment_factor.into())?; - - if !eh_frame && encoding.version == 1 { - let register = self.return_address_register.0 as u8; - if u16::from(register) != self.return_address_register.0 { - return Err(Error::ValueTooLarge); - } - w.write_u8(register)?; - } else { - w.write_uleb128(self.return_address_register.0.into())?; - } - - if augmentation { - let augmentation_length_offset = w.len(); - w.write_u8(0)?; - let augmentation_length_base = w.len(); - - if let Some(eh_pe) = self.lsda_encoding { - w.write_u8(eh_pe.0)?; - } - if let Some((eh_pe, address)) = self.personality { - w.write_u8(eh_pe.0)?; - w.write_eh_pointer(address, eh_pe, encoding.address_size)?; - } - if self.fde_address_encoding != constants::DW_EH_PE_absptr { - w.write_u8(self.fde_address_encoding.0)?; - } - - let augmentation_length = (w.len() - augmentation_length_base) as u64; - debug_assert!(augmentation_length < 0x80); - w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?; - } - - for instruction in &self.instructions { - instruction.write(w, encoding, self)?; - } - - write_nop( - w, - encoding.format.word_size() as usize + w.len() - length_base, - encoding.address_size, - )?; - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, encoding.format)?; - - Ok(offset) - } -} - -/// A frame description entry. There should be one FDE per function. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FrameDescriptionEntry { - /// The initial address of the function. - address: Address, - - /// The length in bytes of the function. - length: u32, - - /// The address of the LSDA. - pub lsda: Option<Address>, - - /// The instructions for this function, ordered by offset. - instructions: Vec<(u32, CallFrameInstruction)>, -} - -impl FrameDescriptionEntry { - /// Create a new frame description entry for a function. - pub fn new(address: Address, length: u32) -> Self { - FrameDescriptionEntry { - address, - length, - lsda: None, - instructions: Vec::new(), - } - } - - /// Add an instruction. - /// - /// Instructions must be added in increasing order of offset, or writing will fail. - pub fn add_instruction(&mut self, offset: u32, instruction: CallFrameInstruction) { - debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset); - self.instructions.push((offset, instruction)); - } - - fn write<W: Writer>( - &self, - w: &mut W, - eh_frame: bool, - cie_offset: usize, - cie: &CommonInformationEntry, - ) -> Result<()> { - let encoding = cie.encoding; - let length_offset = w.write_initial_length(encoding.format)?; - let length_base = w.len(); - - if eh_frame { - // .eh_frame uses a relative offset which doesn't need relocation. - w.write_udata((w.len() - cie_offset) as u64, 4)?; - } else { - w.write_offset( - cie_offset, - SectionId::DebugFrame, - encoding.format.word_size(), - )?; - } - - if cie.fde_address_encoding != constants::DW_EH_PE_absptr { - w.write_eh_pointer( - self.address, - cie.fde_address_encoding, - encoding.address_size, - )?; - w.write_eh_pointer_data( - self.length.into(), - cie.fde_address_encoding.format(), - encoding.address_size, - )?; - } else { - w.write_address(self.address, encoding.address_size)?; - w.write_udata(self.length.into(), encoding.address_size)?; - } - - if cie.has_augmentation() { - let mut augmentation_length = 0u64; - if self.lsda.is_some() { - augmentation_length += u64::from(encoding.address_size); - } - w.write_uleb128(augmentation_length)?; - - debug_assert_eq!(self.lsda.is_some(), cie.lsda_encoding.is_some()); - if let (Some(lsda), Some(lsda_encoding)) = (self.lsda, cie.lsda_encoding) { - w.write_eh_pointer(lsda, lsda_encoding, encoding.address_size)?; - } - } - - let mut prev_offset = 0; - for (offset, instruction) in &self.instructions { - write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?; - prev_offset = *offset; - instruction.write(w, encoding, cie)?; - } - - write_nop( - w, - encoding.format.word_size() as usize + w.len() - length_base, - encoding.address_size, - )?; - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, encoding.format)?; - - Ok(()) - } -} - -/// An instruction in a frame description entry. -/// -/// This may be a CFA definition, a register rule, or some other directive. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub enum CallFrameInstruction { - /// Define the CFA rule to use the provided register and offset. - Cfa(Register, i32), - /// Update the CFA rule to use the provided register. The offset is unchanged. - CfaRegister(Register), - /// Update the CFA rule to use the provided offset. The register is unchanged. - CfaOffset(i32), - /// Define the CFA rule to use the provided expression. - CfaExpression(Expression), - - /// Restore the initial rule for the register. - Restore(Register), - /// The previous value of the register is not recoverable. - Undefined(Register), - /// The register has not been modified. - SameValue(Register), - /// The previous value of the register is saved at address CFA + offset. - Offset(Register, i32), - /// The previous value of the register is CFA + offset. - ValOffset(Register, i32), - /// The previous value of the register is stored in another register. - Register(Register, Register), - /// The previous value of the register is saved at address given by the expression. - Expression(Register, Expression), - /// The previous value of the register is given by the expression. - ValExpression(Register, Expression), - - /// Push all register rules onto a stack. - RememberState, - /// Pop all register rules off the stack. - RestoreState, - /// The size of the arguments that have been pushed onto the stack. - ArgsSize(u32), - - /// AAarch64 extension: negate the `RA_SIGN_STATE` pseudo-register. - NegateRaState, -} - -impl CallFrameInstruction { - fn write<W: Writer>( - &self, - w: &mut W, - encoding: Encoding, - cie: &CommonInformationEntry, - ) -> Result<()> { - match *self { - CallFrameInstruction::Cfa(register, offset) => { - if offset < 0 { - let offset = factored_data_offset(offset, cie.data_alignment_factor)?; - w.write_u8(constants::DW_CFA_def_cfa_sf.0)?; - w.write_uleb128(register.0.into())?; - w.write_sleb128(offset.into())?; - } else { - // Unfactored offset. - w.write_u8(constants::DW_CFA_def_cfa.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(offset as u64)?; - } - } - CallFrameInstruction::CfaRegister(register) => { - w.write_u8(constants::DW_CFA_def_cfa_register.0)?; - w.write_uleb128(register.0.into())?; - } - CallFrameInstruction::CfaOffset(offset) => { - if offset < 0 { - let offset = factored_data_offset(offset, cie.data_alignment_factor)?; - w.write_u8(constants::DW_CFA_def_cfa_offset_sf.0)?; - w.write_sleb128(offset.into())?; - } else { - // Unfactored offset. - w.write_u8(constants::DW_CFA_def_cfa_offset.0)?; - w.write_uleb128(offset as u64)?; - } - } - CallFrameInstruction::CfaExpression(ref expression) => { - w.write_u8(constants::DW_CFA_def_cfa_expression.0)?; - w.write_uleb128(expression.size(encoding, None) as u64)?; - expression.write(w, None, encoding, None)?; - } - CallFrameInstruction::Restore(register) => { - if register.0 < 0x40 { - w.write_u8(constants::DW_CFA_restore.0 | register.0 as u8)?; - } else { - w.write_u8(constants::DW_CFA_restore_extended.0)?; - w.write_uleb128(register.0.into())?; - } - } - CallFrameInstruction::Undefined(register) => { - w.write_u8(constants::DW_CFA_undefined.0)?; - w.write_uleb128(register.0.into())?; - } - CallFrameInstruction::SameValue(register) => { - w.write_u8(constants::DW_CFA_same_value.0)?; - w.write_uleb128(register.0.into())?; - } - CallFrameInstruction::Offset(register, offset) => { - let offset = factored_data_offset(offset, cie.data_alignment_factor)?; - if offset < 0 { - w.write_u8(constants::DW_CFA_offset_extended_sf.0)?; - w.write_uleb128(register.0.into())?; - w.write_sleb128(offset.into())?; - } else if register.0 < 0x40 { - w.write_u8(constants::DW_CFA_offset.0 | register.0 as u8)?; - w.write_uleb128(offset as u64)?; - } else { - w.write_u8(constants::DW_CFA_offset_extended.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(offset as u64)?; - } - } - CallFrameInstruction::ValOffset(register, offset) => { - let offset = factored_data_offset(offset, cie.data_alignment_factor)?; - if offset < 0 { - w.write_u8(constants::DW_CFA_val_offset_sf.0)?; - w.write_uleb128(register.0.into())?; - w.write_sleb128(offset.into())?; - } else { - w.write_u8(constants::DW_CFA_val_offset.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(offset as u64)?; - } - } - CallFrameInstruction::Register(register1, register2) => { - w.write_u8(constants::DW_CFA_register.0)?; - w.write_uleb128(register1.0.into())?; - w.write_uleb128(register2.0.into())?; - } - CallFrameInstruction::Expression(register, ref expression) => { - w.write_u8(constants::DW_CFA_expression.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(expression.size(encoding, None) as u64)?; - expression.write(w, None, encoding, None)?; - } - CallFrameInstruction::ValExpression(register, ref expression) => { - w.write_u8(constants::DW_CFA_val_expression.0)?; - w.write_uleb128(register.0.into())?; - w.write_uleb128(expression.size(encoding, None) as u64)?; - expression.write(w, None, encoding, None)?; - } - CallFrameInstruction::RememberState => { - w.write_u8(constants::DW_CFA_remember_state.0)?; - } - CallFrameInstruction::RestoreState => { - w.write_u8(constants::DW_CFA_restore_state.0)?; - } - CallFrameInstruction::ArgsSize(size) => { - w.write_u8(constants::DW_CFA_GNU_args_size.0)?; - w.write_uleb128(size.into())?; - } - CallFrameInstruction::NegateRaState => { - w.write_u8(constants::DW_CFA_AARCH64_negate_ra_state.0)?; - } - } - Ok(()) - } -} - -fn write_advance_loc<W: Writer>( - w: &mut W, - code_alignment_factor: u8, - prev_offset: u32, - offset: u32, -) -> Result<()> { - if offset == prev_offset { - return Ok(()); - } - let delta = factored_code_delta(prev_offset, offset, code_alignment_factor)?; - if delta < 0x40 { - w.write_u8(constants::DW_CFA_advance_loc.0 | delta as u8)?; - } else if delta < 0x100 { - w.write_u8(constants::DW_CFA_advance_loc1.0)?; - w.write_u8(delta as u8)?; - } else if delta < 0x10000 { - w.write_u8(constants::DW_CFA_advance_loc2.0)?; - w.write_u16(delta as u16)?; - } else { - w.write_u8(constants::DW_CFA_advance_loc4.0)?; - w.write_u32(delta)?; - } - Ok(()) -} - -fn write_nop<W: Writer>(w: &mut W, len: usize, align: u8) -> Result<()> { - debug_assert_eq!(align & (align - 1), 0); - let tail_len = (!len + 1) & (align as usize - 1); - for _ in 0..tail_len { - w.write_u8(constants::DW_CFA_nop.0)?; - } - Ok(()) -} - -fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result<u32> { - if offset < prev_offset { - return Err(Error::InvalidFrameCodeOffset(offset)); - } - let delta = offset - prev_offset; - let factor = u32::from(factor); - let factored_delta = delta / factor; - if delta != factored_delta * factor { - return Err(Error::InvalidFrameCodeOffset(offset)); - } - Ok(factored_delta) -} - -fn factored_data_offset(offset: i32, factor: i8) -> Result<i32> { - let factor = i32::from(factor); - let factored_offset = offset / factor; - if offset != factored_offset * factor { - return Err(Error::InvalidFrameDataOffset(offset)); - } - Ok(factored_offset) -} - -#[cfg(feature = "read")] -pub(crate) mod convert { - use super::*; - use crate::read::{self, Reader}; - use crate::write::{ConvertError, ConvertResult}; - use std::collections::{hash_map, HashMap}; - - impl FrameTable { - /// Create a frame table by reading the data in the given section. - /// - /// `convert_address` is a function to convert read addresses into the `Address` - /// type. For non-relocatable addresses, this function may simply return - /// `Address::Constant(address)`. For relocatable addresses, it is the caller's - /// responsibility to determine the symbol and addend corresponding to the address - /// and return `Address::Symbol { symbol, addend }`. - pub fn from<R, Section>( - frame: &Section, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<FrameTable> - where - R: Reader<Offset = usize>, - Section: read::UnwindSection<R>, - Section::Offset: read::UnwindOffset<usize>, - { - let bases = read::BaseAddresses::default().set_eh_frame(0); - - let mut frame_table = FrameTable::default(); - - let mut cie_ids = HashMap::new(); - let mut entries = frame.entries(&bases); - while let Some(entry) = entries.next()? { - let partial = match entry { - read::CieOrFde::Cie(_) => continue, - read::CieOrFde::Fde(partial) => partial, - }; - - // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only - // stored a reference. - let from_fde = partial.parse(Section::cie_from_offset)?; - let from_cie = from_fde.cie(); - let cie_id = match cie_ids.entry(from_cie.offset()) { - hash_map::Entry::Occupied(o) => *o.get(), - hash_map::Entry::Vacant(e) => { - let cie = - CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?; - let cie_id = frame_table.add_cie(cie); - e.insert(cie_id); - cie_id - } - }; - let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?; - frame_table.add_fde(cie_id, fde); - } - - Ok(frame_table) - } - } - - impl CommonInformationEntry { - fn from<R, Section>( - from_cie: &read::CommonInformationEntry<R>, - frame: &Section, - bases: &read::BaseAddresses, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<CommonInformationEntry> - where - R: Reader<Offset = usize>, - Section: read::UnwindSection<R>, - Section::Offset: read::UnwindOffset<usize>, - { - let mut cie = CommonInformationEntry::new( - from_cie.encoding(), - from_cie.code_alignment_factor() as u8, - from_cie.data_alignment_factor() as i8, - from_cie.return_address_register(), - ); - - cie.personality = match from_cie.personality_with_encoding() { - // We treat these the same because the encoding already determines - // whether it is indirect. - Some((eh_pe, read::Pointer::Direct(p))) - | Some((eh_pe, read::Pointer::Indirect(p))) => { - let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?; - Some((eh_pe, address)) - } - _ => None, - }; - cie.lsda_encoding = from_cie.lsda_encoding(); - cie.fde_address_encoding = from_cie - .fde_address_encoding() - .unwrap_or(constants::DW_EH_PE_absptr); - cie.signal_trampoline = from_cie.is_signal_trampoline(); - - let mut offset = 0; - let mut from_instructions = from_cie.instructions(frame, bases); - while let Some(from_instruction) = from_instructions.next()? { - if let Some(instruction) = CallFrameInstruction::from( - from_instruction, - from_cie, - convert_address, - &mut offset, - )? { - cie.instructions.push(instruction); - } - } - Ok(cie) - } - } - - impl FrameDescriptionEntry { - fn from<R, Section>( - from_fde: &read::FrameDescriptionEntry<R>, - frame: &Section, - bases: &read::BaseAddresses, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<FrameDescriptionEntry> - where - R: Reader<Offset = usize>, - Section: read::UnwindSection<R>, - Section::Offset: read::UnwindOffset<usize>, - { - let address = - convert_address(from_fde.initial_address()).ok_or(ConvertError::InvalidAddress)?; - let length = from_fde.len() as u32; - let mut fde = FrameDescriptionEntry::new(address, length); - - match from_fde.lsda() { - // We treat these the same because the encoding already determines - // whether it is indirect. - Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => { - let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?; - fde.lsda = Some(address); - } - None => {} - } - - let from_cie = from_fde.cie(); - let mut offset = 0; - let mut from_instructions = from_fde.instructions(frame, bases); - while let Some(from_instruction) = from_instructions.next()? { - if let Some(instruction) = CallFrameInstruction::from( - from_instruction, - from_cie, - convert_address, - &mut offset, - )? { - fde.instructions.push((offset, instruction)); - } - } - - Ok(fde) - } - } - - impl CallFrameInstruction { - fn from<R: Reader<Offset = usize>>( - from_instruction: read::CallFrameInstruction<R>, - from_cie: &read::CommonInformationEntry<R>, - convert_address: &dyn Fn(u64) -> Option<Address>, - offset: &mut u32, - ) -> ConvertResult<Option<CallFrameInstruction>> { - let convert_expression = - |x| Expression::from(x, from_cie.encoding(), None, None, None, convert_address); - // TODO: validate integer type conversions - Ok(Some(match from_instruction { - read::CallFrameInstruction::SetLoc { .. } => { - return Err(ConvertError::UnsupportedCfiInstruction); - } - read::CallFrameInstruction::AdvanceLoc { delta } => { - *offset += delta * from_cie.code_alignment_factor() as u32; - return Ok(None); - } - read::CallFrameInstruction::DefCfa { register, offset } => { - CallFrameInstruction::Cfa(register, offset as i32) - } - read::CallFrameInstruction::DefCfaSf { - register, - factored_offset, - } => { - let offset = factored_offset * from_cie.data_alignment_factor(); - CallFrameInstruction::Cfa(register, offset as i32) - } - read::CallFrameInstruction::DefCfaRegister { register } => { - CallFrameInstruction::CfaRegister(register) - } - - read::CallFrameInstruction::DefCfaOffset { offset } => { - CallFrameInstruction::CfaOffset(offset as i32) - } - read::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => { - let offset = factored_offset * from_cie.data_alignment_factor(); - CallFrameInstruction::CfaOffset(offset as i32) - } - read::CallFrameInstruction::DefCfaExpression { expression } => { - CallFrameInstruction::CfaExpression(convert_expression(expression)?) - } - read::CallFrameInstruction::Undefined { register } => { - CallFrameInstruction::Undefined(register) - } - read::CallFrameInstruction::SameValue { register } => { - CallFrameInstruction::SameValue(register) - } - read::CallFrameInstruction::Offset { - register, - factored_offset, - } => { - let offset = factored_offset as i64 * from_cie.data_alignment_factor(); - CallFrameInstruction::Offset(register, offset as i32) - } - read::CallFrameInstruction::OffsetExtendedSf { - register, - factored_offset, - } => { - let offset = factored_offset * from_cie.data_alignment_factor(); - CallFrameInstruction::Offset(register, offset as i32) - } - read::CallFrameInstruction::ValOffset { - register, - factored_offset, - } => { - let offset = factored_offset as i64 * from_cie.data_alignment_factor(); - CallFrameInstruction::ValOffset(register, offset as i32) - } - read::CallFrameInstruction::ValOffsetSf { - register, - factored_offset, - } => { - let offset = factored_offset * from_cie.data_alignment_factor(); - CallFrameInstruction::ValOffset(register, offset as i32) - } - read::CallFrameInstruction::Register { - dest_register, - src_register, - } => CallFrameInstruction::Register(dest_register, src_register), - read::CallFrameInstruction::Expression { - register, - expression, - } => CallFrameInstruction::Expression(register, convert_expression(expression)?), - read::CallFrameInstruction::ValExpression { - register, - expression, - } => CallFrameInstruction::ValExpression(register, convert_expression(expression)?), - read::CallFrameInstruction::Restore { register } => { - CallFrameInstruction::Restore(register) - } - read::CallFrameInstruction::RememberState => CallFrameInstruction::RememberState, - read::CallFrameInstruction::RestoreState => CallFrameInstruction::RestoreState, - read::CallFrameInstruction::ArgsSize { size } => { - CallFrameInstruction::ArgsSize(size as u32) - } - read::CallFrameInstruction::NegateRaState => CallFrameInstruction::NegateRaState, - read::CallFrameInstruction::Nop => return Ok(None), - })) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::arch::X86_64; - use crate::read; - use crate::write::EndianVec; - use crate::{LittleEndian, Vendor}; - - #[test] - fn test_frame_table() { - for &version in &[1, 3, 4] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let mut frames = FrameTable::default(); - - let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); - let cie1_id = frames.add_cie(cie1.clone()); - assert_eq!(cie1_id, frames.add_cie(cie1.clone())); - - let mut cie2 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); - cie2.lsda_encoding = Some(constants::DW_EH_PE_absptr); - cie2.personality = - Some((constants::DW_EH_PE_absptr, Address::Constant(0x1234))); - cie2.signal_trampoline = true; - let cie2_id = frames.add_cie(cie2.clone()); - assert_ne!(cie1_id, cie2_id); - assert_eq!(cie2_id, frames.add_cie(cie2.clone())); - - let fde1 = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); - frames.add_fde(cie1_id, fde1.clone()); - - let fde2 = FrameDescriptionEntry::new(Address::Constant(0x2000), 0x20); - frames.add_fde(cie1_id, fde2.clone()); - - let mut fde3 = FrameDescriptionEntry::new(Address::Constant(0x3000), 0x30); - fde3.lsda = Some(Address::Constant(0x3300)); - frames.add_fde(cie2_id, fde3.clone()); - - let mut fde4 = FrameDescriptionEntry::new(Address::Constant(0x4000), 0x40); - fde4.lsda = Some(Address::Constant(0x4400)); - frames.add_fde(cie2_id, fde4.clone()); - - let mut cie3 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); - cie3.fde_address_encoding = constants::DW_EH_PE_pcrel; - cie3.lsda_encoding = Some(constants::DW_EH_PE_pcrel); - cie3.personality = Some((constants::DW_EH_PE_pcrel, Address::Constant(0x1235))); - cie3.signal_trampoline = true; - let cie3_id = frames.add_cie(cie3.clone()); - assert_ne!(cie2_id, cie3_id); - assert_eq!(cie3_id, frames.add_cie(cie3.clone())); - - let mut fde5 = FrameDescriptionEntry::new(Address::Constant(0x5000), 0x50); - fde5.lsda = Some(Address::Constant(0x5500)); - frames.add_fde(cie3_id, fde5.clone()); - - // Test writing `.debug_frame`. - let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); - frames.write_debug_frame(&mut debug_frame).unwrap(); - - let mut read_debug_frame = - read::DebugFrame::new(debug_frame.slice(), LittleEndian); - read_debug_frame.set_address_size(address_size); - let convert_frames = FrameTable::from(&read_debug_frame, &|address| { - Some(Address::Constant(address)) - }) - .unwrap(); - assert_eq!(frames.cies, convert_frames.cies); - assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); - for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) { - assert_eq!(a.1, b.1); - } - - if version == 1 { - // Test writing `.eh_frame`. - let mut eh_frame = EhFrame::from(EndianVec::new(LittleEndian)); - frames.write_eh_frame(&mut eh_frame).unwrap(); - - let mut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian); - read_eh_frame.set_address_size(address_size); - let convert_frames = FrameTable::from(&read_eh_frame, &|address| { - Some(Address::Constant(address)) - }) - .unwrap(); - assert_eq!(frames.cies, convert_frames.cies); - assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); - for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) { - assert_eq!(a.1, b.1); - } - } - } - } - } - } - - #[test] - fn test_frame_instruction() { - let mut expression = Expression::new(); - expression.op_constu(0); - - let cie_instructions = [ - CallFrameInstruction::Cfa(X86_64::RSP, 8), - CallFrameInstruction::Offset(X86_64::RA, -8), - ]; - - let fde_instructions = [ - (0, CallFrameInstruction::Cfa(X86_64::RSP, 0)), - (0, CallFrameInstruction::Cfa(X86_64::RSP, -8)), - (2, CallFrameInstruction::CfaRegister(X86_64::RBP)), - (4, CallFrameInstruction::CfaOffset(8)), - (4, CallFrameInstruction::CfaOffset(0)), - (4, CallFrameInstruction::CfaOffset(-8)), - (6, CallFrameInstruction::CfaExpression(expression.clone())), - (8, CallFrameInstruction::Restore(Register(1))), - (8, CallFrameInstruction::Restore(Register(101))), - (10, CallFrameInstruction::Undefined(Register(2))), - (12, CallFrameInstruction::SameValue(Register(3))), - (14, CallFrameInstruction::Offset(Register(4), 16)), - (14, CallFrameInstruction::Offset(Register(104), 16)), - (16, CallFrameInstruction::ValOffset(Register(5), -24)), - (16, CallFrameInstruction::ValOffset(Register(5), 24)), - (18, CallFrameInstruction::Register(Register(6), Register(7))), - ( - 20, - CallFrameInstruction::Expression(Register(8), expression.clone()), - ), - ( - 22, - CallFrameInstruction::ValExpression(Register(9), expression.clone()), - ), - (24 + 0x80, CallFrameInstruction::RememberState), - (26 + 0x280, CallFrameInstruction::RestoreState), - (28 + 0x20280, CallFrameInstruction::ArgsSize(23)), - ]; - - let fde_instructions_aarch64 = [(0, CallFrameInstruction::NegateRaState)]; - - for &version in &[1, 3, 4] { - for &address_size in &[4, 8] { - for &vendor in &[Vendor::Default, Vendor::AArch64] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let mut frames = FrameTable::default(); - - let mut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA); - for i in &cie_instructions { - cie.add_instruction(i.clone()); - } - let cie_id = frames.add_cie(cie); - - let mut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); - for (o, i) in &fde_instructions { - fde.add_instruction(*o, i.clone()); - } - frames.add_fde(cie_id, fde); - - if vendor == Vendor::AArch64 { - let mut fde = - FrameDescriptionEntry::new(Address::Constant(0x2000), 0x10); - for (o, i) in &fde_instructions_aarch64 { - fde.add_instruction(*o, i.clone()); - } - frames.add_fde(cie_id, fde); - } - - let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); - frames.write_debug_frame(&mut debug_frame).unwrap(); - - let mut read_debug_frame = - read::DebugFrame::new(debug_frame.slice(), LittleEndian); - read_debug_frame.set_address_size(address_size); - read_debug_frame.set_vendor(vendor); - let frames = FrameTable::from(&read_debug_frame, &|address| { - Some(Address::Constant(address)) - }) - .unwrap(); - - assert_eq!( - &frames.cies.get_index(0).unwrap().instructions, - &cie_instructions - ); - assert_eq!(&frames.fdes[0].1.instructions, &fde_instructions); - if vendor == Vendor::AArch64 { - assert_eq!(&frames.fdes[1].1.instructions, &fde_instructions_aarch64); - } - } - } - } - } - } -} diff --git a/vendor/gimli/src/write/dwarf.rs b/vendor/gimli/src/write/dwarf.rs deleted file mode 100644 index ea50712..0000000 --- a/vendor/gimli/src/write/dwarf.rs +++ /dev/null @@ -1,138 +0,0 @@ -use alloc::vec::Vec; - -use crate::common::Encoding; -use crate::write::{ - AbbreviationTable, LineProgram, LineStringTable, Result, Sections, StringTable, Unit, - UnitTable, Writer, -}; - -/// Writable DWARF information for more than one unit. -#[derive(Debug, Default)] -pub struct Dwarf { - /// A table of units. These are primarily stored in the `.debug_info` section, - /// but they also contain information that is stored in other sections. - pub units: UnitTable, - - /// Extra line number programs that are not associated with a unit. - /// - /// These should only be used when generating DWARF5 line-only debug - /// information. - pub line_programs: Vec<LineProgram>, - - /// A table of strings that will be stored in the `.debug_line_str` section. - pub line_strings: LineStringTable, - - /// A table of strings that will be stored in the `.debug_str` section. - pub strings: StringTable, -} - -impl Dwarf { - /// Create a new `Dwarf` instance. - #[inline] - pub fn new() -> Self { - Self::default() - } - - /// Write the DWARF information to the given sections. - pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> { - let line_strings = self.line_strings.write(&mut sections.debug_line_str)?; - let strings = self.strings.write(&mut sections.debug_str)?; - self.units.write(sections, &line_strings, &strings)?; - for line_program in &self.line_programs { - line_program.write( - &mut sections.debug_line, - line_program.encoding(), - &line_strings, - &strings, - )?; - } - Ok(()) - } -} - -/// Writable DWARF information for a single unit. -#[derive(Debug)] -pub struct DwarfUnit { - /// A unit. This is primarily stored in the `.debug_info` section, - /// but also contains information that is stored in other sections. - pub unit: Unit, - - /// A table of strings that will be stored in the `.debug_line_str` section. - pub line_strings: LineStringTable, - - /// A table of strings that will be stored in the `.debug_str` section. - pub strings: StringTable, -} - -impl DwarfUnit { - /// Create a new `DwarfUnit`. - /// - /// Note: you should set `self.unit.line_program` after creation. - /// This cannot be done earlier because it may need to reference - /// `self.line_strings`. - pub fn new(encoding: Encoding) -> Self { - let unit = Unit::new(encoding, LineProgram::none()); - DwarfUnit { - unit, - line_strings: LineStringTable::default(), - strings: StringTable::default(), - } - } - - /// Write the DWARf information to the given sections. - pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> { - let line_strings = self.line_strings.write(&mut sections.debug_line_str)?; - let strings = self.strings.write(&mut sections.debug_str)?; - - let abbrev_offset = sections.debug_abbrev.offset(); - let mut abbrevs = AbbreviationTable::default(); - - self.unit.write( - sections, - abbrev_offset, - &mut abbrevs, - &line_strings, - &strings, - )?; - // None should exist because we didn't give out any UnitId. - assert!(sections.debug_info_refs.is_empty()); - assert!(sections.debug_loc_refs.is_empty()); - assert!(sections.debug_loclists_refs.is_empty()); - - abbrevs.write(&mut sections.debug_abbrev)?; - Ok(()) - } -} - -#[cfg(feature = "read")] -pub(crate) mod convert { - use super::*; - use crate::read::{self, Reader}; - use crate::write::{Address, ConvertResult}; - - impl Dwarf { - /// Create a `write::Dwarf` by converting a `read::Dwarf`. - /// - /// `convert_address` is a function to convert read addresses into the `Address` - /// type. For non-relocatable addresses, this function may simply return - /// `Address::Constant(address)`. For relocatable addresses, it is the caller's - /// responsibility to determine the symbol and addend corresponding to the address - /// and return `Address::Symbol { symbol, addend }`. - pub fn from<R: Reader<Offset = usize>>( - dwarf: &read::Dwarf<R>, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<Dwarf> { - let mut line_strings = LineStringTable::default(); - let mut strings = StringTable::default(); - let units = UnitTable::from(dwarf, &mut line_strings, &mut strings, convert_address)?; - // TODO: convert the line programs that were not referenced by a unit. - let line_programs = Vec::new(); - Ok(Dwarf { - units, - line_programs, - line_strings, - strings, - }) - } - } -} diff --git a/vendor/gimli/src/write/endian_vec.rs b/vendor/gimli/src/write/endian_vec.rs deleted file mode 100644 index 7b04060..0000000 --- a/vendor/gimli/src/write/endian_vec.rs +++ /dev/null @@ -1,117 +0,0 @@ -use alloc::vec::Vec; -use std::mem; - -use crate::endianity::Endianity; -use crate::write::{Error, Result, Writer}; - -/// A `Vec<u8>` with endianity metadata. -/// -/// This implements the `Writer` trait, which is used for all writing of DWARF sections. -#[derive(Debug, Clone)] -pub struct EndianVec<Endian> -where - Endian: Endianity, -{ - vec: Vec<u8>, - endian: Endian, -} - -impl<Endian> EndianVec<Endian> -where - Endian: Endianity, -{ - /// Construct an empty `EndianVec` with the given endianity. - pub fn new(endian: Endian) -> EndianVec<Endian> { - EndianVec { - vec: Vec::new(), - endian, - } - } - - /// Return a reference to the raw slice. - pub fn slice(&self) -> &[u8] { - &self.vec - } - - /// Convert into a `Vec<u8>`. - pub fn into_vec(self) -> Vec<u8> { - self.vec - } - - /// Take any written data out of the `EndianVec`, leaving an empty `Vec` in its place. - pub fn take(&mut self) -> Vec<u8> { - let mut vec = Vec::new(); - mem::swap(&mut self.vec, &mut vec); - vec - } -} - -impl<Endian> Writer for EndianVec<Endian> -where - Endian: Endianity, -{ - type Endian = Endian; - - #[inline] - fn endian(&self) -> Self::Endian { - self.endian - } - - #[inline] - fn len(&self) -> usize { - self.vec.len() - } - - fn write(&mut self, bytes: &[u8]) -> Result<()> { - self.vec.extend(bytes); - Ok(()) - } - - fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { - if offset > self.vec.len() { - return Err(Error::OffsetOutOfBounds); - } - let to = &mut self.vec[offset..]; - if bytes.len() > to.len() { - return Err(Error::LengthOutOfBounds); - } - let to = &mut to[..bytes.len()]; - to.copy_from_slice(bytes); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::LittleEndian; - - #[test] - fn test_endian_vec() { - let mut w = EndianVec::new(LittleEndian); - assert_eq!(w.endian(), LittleEndian); - assert_eq!(w.len(), 0); - - w.write(&[1, 2]).unwrap(); - assert_eq!(w.slice(), &[1, 2]); - assert_eq!(w.len(), 2); - - w.write(&[3, 4, 5]).unwrap(); - assert_eq!(w.slice(), &[1, 2, 3, 4, 5]); - assert_eq!(w.len(), 5); - - w.write_at(0, &[6, 7]).unwrap(); - assert_eq!(w.slice(), &[6, 7, 3, 4, 5]); - assert_eq!(w.len(), 5); - - w.write_at(3, &[8, 9]).unwrap(); - assert_eq!(w.slice(), &[6, 7, 3, 8, 9]); - assert_eq!(w.len(), 5); - - assert_eq!(w.write_at(4, &[6, 7]), Err(Error::LengthOutOfBounds)); - assert_eq!(w.write_at(5, &[6, 7]), Err(Error::LengthOutOfBounds)); - assert_eq!(w.write_at(6, &[6, 7]), Err(Error::OffsetOutOfBounds)); - - assert_eq!(w.into_vec(), vec![6, 7, 3, 8, 9]); - } -} diff --git a/vendor/gimli/src/write/line.rs b/vendor/gimli/src/write/line.rs deleted file mode 100644 index c88b735..0000000 --- a/vendor/gimli/src/write/line.rs +++ /dev/null @@ -1,1957 +0,0 @@ -use alloc::vec::Vec; -use indexmap::{IndexMap, IndexSet}; -use std::ops::{Deref, DerefMut}; - -use crate::common::{DebugLineOffset, Encoding, Format, LineEncoding, SectionId}; -use crate::constants; -use crate::leb128; -use crate::write::{ - Address, DebugLineStrOffsets, DebugStrOffsets, Error, LineStringId, LineStringTable, Result, - Section, StringId, Writer, -}; - -/// The number assigned to the first special opcode. -// -// We output all instructions for all DWARF versions, since readers -// should be able to ignore instructions they don't support. -const OPCODE_BASE: u8 = 13; - -/// A line number program. -#[derive(Debug, Clone)] -pub struct LineProgram { - /// True if this line program was created with `LineProgram::none()`. - none: bool, - encoding: Encoding, - line_encoding: LineEncoding, - - /// A list of source directory path names. - /// - /// If a path is relative, then the directory is located relative to the working - /// directory of the compilation unit. - /// - /// The first entry is for the working directory of the compilation unit. - directories: IndexSet<LineString>, - - /// A list of source file entries. - /// - /// Each entry has a path name and a directory. - /// - /// If a path is a relative, then the file is located relative to the - /// directory. Otherwise the directory is meaningless. - /// - /// Does not include comp_file, even for version >= 5. - files: IndexMap<(LineString, DirectoryId), FileInfo>, - - /// The primary source file of the compilation unit. - /// This is required for version >= 5, but we never reference it elsewhere - /// because DWARF defines DW_AT_decl_file=0 to mean not specified. - comp_file: (LineString, FileInfo), - - /// True if the file entries may have valid timestamps. - /// - /// Entries may still have a timestamp of 0 even if this is set. - /// For version <= 4, this is ignored. - /// For version 5, this controls whether to emit `DW_LNCT_timestamp`. - pub file_has_timestamp: bool, - - /// True if the file entries may have valid sizes. - /// - /// Entries may still have a size of 0 even if this is set. - /// For version <= 4, this is ignored. - /// For version 5, this controls whether to emit `DW_LNCT_size`. - pub file_has_size: bool, - - /// True if the file entries have valid MD5 checksums. - /// - /// For version <= 4, this is ignored. - /// For version 5, this controls whether to emit `DW_LNCT_MD5`. - pub file_has_md5: bool, - - prev_row: LineRow, - row: LineRow, - // TODO: this probably should be either rows or sequences instead - instructions: Vec<LineInstruction>, - in_sequence: bool, -} - -impl LineProgram { - /// Create a new `LineProgram`. - /// - /// `comp_dir` defines the working directory of the compilation unit, - /// and must be the same as the `DW_AT_comp_dir` attribute - /// of the compilation unit DIE. - /// - /// `comp_file` and `comp_file_info` define the primary source file - /// of the compilation unit and must be the same as the `DW_AT_name` - /// attribute of the compilation unit DIE. - /// - /// # Panics - /// - /// Panics if `line_encoding.line_base` > 0. - /// - /// Panics if `line_encoding.line_base` + `line_encoding.line_range` <= 0. - /// - /// Panics if `comp_dir` is empty or contains a null byte. - /// - /// Panics if `comp_file` is empty or contains a null byte. - pub fn new( - encoding: Encoding, - line_encoding: LineEncoding, - comp_dir: LineString, - comp_file: LineString, - comp_file_info: Option<FileInfo>, - ) -> LineProgram { - // We require a special opcode for a line advance of 0. - // See the debug_asserts in generate_row(). - assert!(line_encoding.line_base <= 0); - assert!(line_encoding.line_base + line_encoding.line_range as i8 > 0); - let mut program = LineProgram { - none: false, - encoding, - line_encoding, - directories: IndexSet::new(), - files: IndexMap::new(), - comp_file: (comp_file, comp_file_info.unwrap_or_default()), - prev_row: LineRow::initial_state(line_encoding), - row: LineRow::initial_state(line_encoding), - instructions: Vec::new(), - in_sequence: false, - file_has_timestamp: false, - file_has_size: false, - file_has_md5: false, - }; - // For all DWARF versions, directory index 0 is comp_dir. - // For version <= 4, the entry is implicit. We still add - // it here so that we use it, but we don't emit it. - program.add_directory(comp_dir); - program - } - - /// Create a new `LineProgram` with no fields set. - /// - /// This can be used when the `LineProgram` will not be used. - /// - /// You should not attempt to add files or line instructions to - /// this line program, or write it to the `.debug_line` section. - pub fn none() -> Self { - let line_encoding = LineEncoding::default(); - LineProgram { - none: true, - encoding: Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 0, - }, - line_encoding, - directories: IndexSet::new(), - files: IndexMap::new(), - comp_file: (LineString::String(Vec::new()), FileInfo::default()), - prev_row: LineRow::initial_state(line_encoding), - row: LineRow::initial_state(line_encoding), - instructions: Vec::new(), - in_sequence: false, - file_has_timestamp: false, - file_has_size: false, - file_has_md5: false, - } - } - - /// Return true if this line program was created with `LineProgram::none()`. - #[inline] - pub fn is_none(&self) -> bool { - self.none - } - - /// Return the encoding parameters for this line program. - #[inline] - pub fn encoding(&self) -> Encoding { - self.encoding - } - - /// Return the DWARF version for this line program. - #[inline] - pub fn version(&self) -> u16 { - self.encoding.version - } - - /// Return the address size in bytes for this line program. - #[inline] - pub fn address_size(&self) -> u8 { - self.encoding.address_size - } - - /// Return the DWARF format for this line program. - #[inline] - pub fn format(&self) -> Format { - self.encoding.format - } - - /// Return the id for the working directory of the compilation unit. - #[inline] - pub fn default_directory(&self) -> DirectoryId { - DirectoryId(0) - } - - /// Add a directory entry and return its id. - /// - /// If the directory already exists, then return the id of the existing entry. - /// - /// If the path is relative, then the directory is located relative to the working - /// directory of the compilation unit. - /// - /// # Panics - /// - /// Panics if `directory` is empty or contains a null byte. - pub fn add_directory(&mut self, directory: LineString) -> DirectoryId { - if let LineString::String(ref val) = directory { - // For DWARF version <= 4, directories must not be empty. - // The first directory isn't emitted so skip the check for it. - if self.encoding.version <= 4 && !self.directories.is_empty() { - assert!(!val.is_empty()); - } - assert!(!val.contains(&0)); - } - let (index, _) = self.directories.insert_full(directory); - DirectoryId(index) - } - - /// Get a reference to a directory entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get_directory(&self, id: DirectoryId) -> &LineString { - self.directories.get_index(id.0).unwrap() - } - - /// Add a file entry and return its id. - /// - /// If the file already exists, then return the id of the existing entry. - /// - /// If the file path is relative, then the file is located relative - /// to the directory. Otherwise the directory is meaningless, but it - /// is still used as a key for file entries. - /// - /// If `info` is `None`, then new entries are assigned - /// default information, and existing entries are unmodified. - /// - /// If `info` is not `None`, then it is always assigned to the - /// entry, even if the entry already exists. - /// - /// # Panics - /// - /// Panics if 'file' is empty or contains a null byte. - pub fn add_file( - &mut self, - file: LineString, - directory: DirectoryId, - info: Option<FileInfo>, - ) -> FileId { - if let LineString::String(ref val) = file { - assert!(!val.is_empty()); - assert!(!val.contains(&0)); - } - - let key = (file, directory); - let index = if let Some(info) = info { - let (index, _) = self.files.insert_full(key, info); - index - } else { - let entry = self.files.entry(key); - let index = entry.index(); - entry.or_default(); - index - }; - FileId::new(index) - } - - /// Get a reference to a file entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get_file(&self, id: FileId) -> (&LineString, DirectoryId) { - match id.index() { - None => (&self.comp_file.0, DirectoryId(0)), - Some(index) => self - .files - .get_index(index) - .map(|entry| (&(entry.0).0, (entry.0).1)) - .unwrap(), - } - } - - /// Get a reference to the info for a file entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get_file_info(&self, id: FileId) -> &FileInfo { - match id.index() { - None => &self.comp_file.1, - Some(index) => self.files.get_index(index).map(|entry| entry.1).unwrap(), - } - } - - /// Get a mutable reference to the info for a file entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get_file_info_mut(&mut self, id: FileId) -> &mut FileInfo { - match id.index() { - None => &mut self.comp_file.1, - Some(index) => self - .files - .get_index_mut(index) - .map(|entry| entry.1) - .unwrap(), - } - } - - /// Begin a new sequence and set its base address. - /// - /// # Panics - /// - /// Panics if a sequence has already begun. - pub fn begin_sequence(&mut self, address: Option<Address>) { - assert!(!self.in_sequence); - self.in_sequence = true; - if let Some(address) = address { - self.instructions.push(LineInstruction::SetAddress(address)); - } - } - - /// End the sequence, and reset the row to its default values. - /// - /// Only the `address_offset` and op_index` fields of the current row are used. - /// - /// # Panics - /// - /// Panics if a sequence has not begun. - pub fn end_sequence(&mut self, address_offset: u64) { - assert!(self.in_sequence); - self.in_sequence = false; - self.row.address_offset = address_offset; - let op_advance = self.op_advance(); - if op_advance != 0 { - self.instructions - .push(LineInstruction::AdvancePc(op_advance)); - } - self.instructions.push(LineInstruction::EndSequence); - self.prev_row = LineRow::initial_state(self.line_encoding); - self.row = LineRow::initial_state(self.line_encoding); - } - - /// Return true if a sequence has begun. - #[inline] - pub fn in_sequence(&self) -> bool { - self.in_sequence - } - - /// Returns a reference to the data for the current row. - #[inline] - pub fn row(&mut self) -> &mut LineRow { - &mut self.row - } - - /// Generates the line number information instructions for the current row. - /// - /// After the instructions are generated, it sets `discriminator` to 0, and sets - /// `basic_block`, `prologue_end`, and `epilogue_begin` to false. - /// - /// # Panics - /// - /// Panics if a sequence has not begun. - /// Panics if the address_offset decreases. - pub fn generate_row(&mut self) { - assert!(self.in_sequence); - - // Output fields that are reset on every row. - if self.row.discriminator != 0 { - self.instructions - .push(LineInstruction::SetDiscriminator(self.row.discriminator)); - self.row.discriminator = 0; - } - if self.row.basic_block { - self.instructions.push(LineInstruction::SetBasicBlock); - self.row.basic_block = false; - } - if self.row.prologue_end { - self.instructions.push(LineInstruction::SetPrologueEnd); - self.row.prologue_end = false; - } - if self.row.epilogue_begin { - self.instructions.push(LineInstruction::SetEpilogueBegin); - self.row.epilogue_begin = false; - } - - // Output fields that are not reset on every row. - if self.row.is_statement != self.prev_row.is_statement { - self.instructions.push(LineInstruction::NegateStatement); - } - if self.row.file != self.prev_row.file { - self.instructions - .push(LineInstruction::SetFile(self.row.file)); - } - if self.row.column != self.prev_row.column { - self.instructions - .push(LineInstruction::SetColumn(self.row.column)); - } - if self.row.isa != self.prev_row.isa { - self.instructions - .push(LineInstruction::SetIsa(self.row.isa)); - } - - // Advance the line, address, and operation index. - let line_base = i64::from(self.line_encoding.line_base) as u64; - let line_range = u64::from(self.line_encoding.line_range); - let line_advance = self.row.line as i64 - self.prev_row.line as i64; - let op_advance = self.op_advance(); - - // Default to special advances of 0. - let special_base = u64::from(OPCODE_BASE); - // TODO: handle lack of special opcodes for 0 line advance - debug_assert!(self.line_encoding.line_base <= 0); - debug_assert!(self.line_encoding.line_base + self.line_encoding.line_range as i8 >= 0); - let special_default = special_base.wrapping_sub(line_base); - let mut special = special_default; - let mut use_special = false; - - if line_advance != 0 { - let special_line = (line_advance as u64).wrapping_sub(line_base); - if special_line < line_range { - special = special_base + special_line; - use_special = true; - } else { - self.instructions - .push(LineInstruction::AdvanceLine(line_advance)); - } - } - - if op_advance != 0 { - // Using ConstAddPc can save a byte. - let (special_op_advance, const_add_pc) = if special + op_advance * line_range <= 255 { - (op_advance, false) - } else { - let op_range = (255 - special_base) / line_range; - (op_advance - op_range, true) - }; - - let special_op = special_op_advance * line_range; - if special + special_op <= 255 { - special += special_op; - use_special = true; - if const_add_pc { - self.instructions.push(LineInstruction::ConstAddPc); - } - } else { - self.instructions - .push(LineInstruction::AdvancePc(op_advance)); - } - } - - if use_special && special != special_default { - debug_assert!(special >= special_base); - debug_assert!(special <= 255); - self.instructions - .push(LineInstruction::Special(special as u8)); - } else { - self.instructions.push(LineInstruction::Copy); - } - - self.prev_row = self.row; - } - - fn op_advance(&self) -> u64 { - debug_assert!(self.row.address_offset >= self.prev_row.address_offset); - let mut address_advance = self.row.address_offset - self.prev_row.address_offset; - if self.line_encoding.minimum_instruction_length != 1 { - debug_assert_eq!( - self.row.address_offset % u64::from(self.line_encoding.minimum_instruction_length), - 0 - ); - address_advance /= u64::from(self.line_encoding.minimum_instruction_length); - } - address_advance * u64::from(self.line_encoding.maximum_operations_per_instruction) - + self.row.op_index - - self.prev_row.op_index - } - - /// Returns true if the line number program has no instructions. - /// - /// Does not check the file or directory entries. - #[inline] - pub fn is_empty(&self) -> bool { - self.instructions.is_empty() - } - - /// Write the line number program to the given section. - /// - /// # Panics - /// - /// Panics if `self.is_none()`. - pub fn write<W: Writer>( - &self, - w: &mut DebugLine<W>, - encoding: Encoding, - debug_line_str_offsets: &DebugLineStrOffsets, - debug_str_offsets: &DebugStrOffsets, - ) -> Result<DebugLineOffset> { - assert!(!self.is_none()); - - if encoding.version < self.version() - || encoding.format != self.format() - || encoding.address_size != self.address_size() - { - return Err(Error::IncompatibleLineProgramEncoding); - } - - let offset = w.offset(); - - let length_offset = w.write_initial_length(self.format())?; - let length_base = w.len(); - - if self.version() < 2 || self.version() > 5 { - return Err(Error::UnsupportedVersion(self.version())); - } - w.write_u16(self.version())?; - - if self.version() >= 5 { - w.write_u8(self.address_size())?; - // Segment selector size. - w.write_u8(0)?; - } - - let header_length_offset = w.len(); - w.write_udata(0, self.format().word_size())?; - let header_length_base = w.len(); - - w.write_u8(self.line_encoding.minimum_instruction_length)?; - if self.version() >= 4 { - w.write_u8(self.line_encoding.maximum_operations_per_instruction)?; - } else if self.line_encoding.maximum_operations_per_instruction != 1 { - return Err(Error::NeedVersion(4)); - }; - w.write_u8(if self.line_encoding.default_is_stmt { - 1 - } else { - 0 - })?; - w.write_u8(self.line_encoding.line_base as u8)?; - w.write_u8(self.line_encoding.line_range)?; - w.write_u8(OPCODE_BASE)?; - w.write(&[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1])?; - - if self.version() <= 4 { - // The first directory is stored as DW_AT_comp_dir. - for dir in self.directories.iter().skip(1) { - dir.write( - w, - constants::DW_FORM_string, - self.encoding, - debug_line_str_offsets, - debug_str_offsets, - )?; - } - w.write_u8(0)?; - - for ((file, dir), info) in self.files.iter() { - file.write( - w, - constants::DW_FORM_string, - self.encoding, - debug_line_str_offsets, - debug_str_offsets, - )?; - w.write_uleb128(dir.0 as u64)?; - w.write_uleb128(info.timestamp)?; - w.write_uleb128(info.size)?; - } - w.write_u8(0)?; - } else { - // Directory entry formats (only ever 1). - w.write_u8(1)?; - w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; - let dir_form = self.directories.get_index(0).unwrap().form(); - w.write_uleb128(dir_form.0.into())?; - - // Directory entries. - w.write_uleb128(self.directories.len() as u64)?; - for dir in self.directories.iter() { - dir.write( - w, - dir_form, - self.encoding, - debug_line_str_offsets, - debug_str_offsets, - )?; - } - - // File name entry formats. - let count = 2 - + if self.file_has_timestamp { 1 } else { 0 } - + if self.file_has_size { 1 } else { 0 } - + if self.file_has_md5 { 1 } else { 0 }; - w.write_u8(count)?; - w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; - let file_form = self.comp_file.0.form(); - w.write_uleb128(file_form.0.into())?; - w.write_uleb128(u64::from(constants::DW_LNCT_directory_index.0))?; - w.write_uleb128(constants::DW_FORM_udata.0.into())?; - if self.file_has_timestamp { - w.write_uleb128(u64::from(constants::DW_LNCT_timestamp.0))?; - w.write_uleb128(constants::DW_FORM_udata.0.into())?; - } - if self.file_has_size { - w.write_uleb128(u64::from(constants::DW_LNCT_size.0))?; - w.write_uleb128(constants::DW_FORM_udata.0.into())?; - } - if self.file_has_md5 { - w.write_uleb128(u64::from(constants::DW_LNCT_MD5.0))?; - w.write_uleb128(constants::DW_FORM_data16.0.into())?; - } - - // File name entries. - w.write_uleb128(self.files.len() as u64 + 1)?; - let mut write_file = |file: &LineString, dir: DirectoryId, info: &FileInfo| { - file.write( - w, - file_form, - self.encoding, - debug_line_str_offsets, - debug_str_offsets, - )?; - w.write_uleb128(dir.0 as u64)?; - if self.file_has_timestamp { - w.write_uleb128(info.timestamp)?; - } - if self.file_has_size { - w.write_uleb128(info.size)?; - } - if self.file_has_md5 { - w.write(&info.md5)?; - } - Ok(()) - }; - write_file(&self.comp_file.0, DirectoryId(0), &self.comp_file.1)?; - for ((file, dir), info) in self.files.iter() { - write_file(file, *dir, info)?; - } - } - - let header_length = (w.len() - header_length_base) as u64; - w.write_udata_at( - header_length_offset, - header_length, - self.format().word_size(), - )?; - - for instruction in &self.instructions { - instruction.write(w, self.address_size())?; - } - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, self.format())?; - - Ok(offset) - } -} - -/// A row in the line number table that corresponds to a machine instruction. -#[derive(Debug, Clone, Copy)] -pub struct LineRow { - /// The offset of the instruction from the start address of the sequence. - pub address_offset: u64, - /// The index of an operation within a VLIW instruction. - /// - /// The index of the first operation is 0. - /// Set to 0 for non-VLIW instructions. - pub op_index: u64, - - /// The source file corresponding to the instruction. - pub file: FileId, - /// The line number within the source file. - /// - /// Lines are numbered beginning at 1. Set to 0 if there is no source line. - pub line: u64, - /// The column number within the source line. - /// - /// Columns are numbered beginning at 1. Set to 0 for the "left edge" of the line. - pub column: u64, - /// An additional discriminator used to distinguish between source locations. - /// This value is assigned arbitrarily by the DWARF producer. - pub discriminator: u64, - - /// Set to true if the instruction is a recommended breakpoint for a statement. - pub is_statement: bool, - /// Set to true if the instruction is the beginning of a basic block. - pub basic_block: bool, - /// Set to true if the instruction is a recommended breakpoint at the entry of a - /// function. - pub prologue_end: bool, - /// Set to true if the instruction is a recommended breakpoint prior to the exit of - /// a function. - pub epilogue_begin: bool, - - /// The instruction set architecture of the instruction. - /// - /// Set to 0 for the default ISA. Other values are defined by the architecture ABI. - pub isa: u64, -} - -impl LineRow { - /// Return the initial state as specified in the DWARF standard. - fn initial_state(line_encoding: LineEncoding) -> Self { - LineRow { - address_offset: 0, - op_index: 0, - - file: FileId::initial_state(), - line: 1, - column: 0, - discriminator: 0, - - is_statement: line_encoding.default_is_stmt, - basic_block: false, - prologue_end: false, - epilogue_begin: false, - - isa: 0, - } - } -} - -/// An instruction in a line number program. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum LineInstruction { - // Special opcodes - Special(u8), - - // Standard opcodes - Copy, - AdvancePc(u64), - AdvanceLine(i64), - SetFile(FileId), - SetColumn(u64), - NegateStatement, - SetBasicBlock, - ConstAddPc, - // DW_LNS_fixed_advance_pc is not supported. - SetPrologueEnd, - SetEpilogueBegin, - SetIsa(u64), - - // Extended opcodes - EndSequence, - // TODO: this doubles the size of this enum. - SetAddress(Address), - // DW_LNE_define_file is not supported. - SetDiscriminator(u64), -} - -impl LineInstruction { - /// Write the line number instruction to the given section. - fn write<W: Writer>(self, w: &mut DebugLine<W>, address_size: u8) -> Result<()> { - use self::LineInstruction::*; - match self { - Special(val) => w.write_u8(val)?, - Copy => w.write_u8(constants::DW_LNS_copy.0)?, - AdvancePc(val) => { - w.write_u8(constants::DW_LNS_advance_pc.0)?; - w.write_uleb128(val)?; - } - AdvanceLine(val) => { - w.write_u8(constants::DW_LNS_advance_line.0)?; - w.write_sleb128(val)?; - } - SetFile(val) => { - w.write_u8(constants::DW_LNS_set_file.0)?; - w.write_uleb128(val.raw())?; - } - SetColumn(val) => { - w.write_u8(constants::DW_LNS_set_column.0)?; - w.write_uleb128(val)?; - } - NegateStatement => w.write_u8(constants::DW_LNS_negate_stmt.0)?, - SetBasicBlock => w.write_u8(constants::DW_LNS_set_basic_block.0)?, - ConstAddPc => w.write_u8(constants::DW_LNS_const_add_pc.0)?, - SetPrologueEnd => w.write_u8(constants::DW_LNS_set_prologue_end.0)?, - SetEpilogueBegin => w.write_u8(constants::DW_LNS_set_epilogue_begin.0)?, - SetIsa(val) => { - w.write_u8(constants::DW_LNS_set_isa.0)?; - w.write_uleb128(val)?; - } - EndSequence => { - w.write_u8(0)?; - w.write_uleb128(1)?; - w.write_u8(constants::DW_LNE_end_sequence.0)?; - } - SetAddress(address) => { - w.write_u8(0)?; - w.write_uleb128(1 + u64::from(address_size))?; - w.write_u8(constants::DW_LNE_set_address.0)?; - w.write_address(address, address_size)?; - } - SetDiscriminator(val) => { - let mut bytes = [0u8; 10]; - // bytes is long enough so this will never fail. - let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); - w.write_u8(0)?; - w.write_uleb128(1 + len as u64)?; - w.write_u8(constants::DW_LNE_set_discriminator.0)?; - w.write(&bytes[..len])?; - } - } - Ok(()) - } -} - -/// A string value for use in defining paths in line number programs. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum LineString { - /// A slice of bytes representing a string. Must not include null bytes. - /// Not guaranteed to be UTF-8 or anything like that. - String(Vec<u8>), - - /// A reference to a string in the `.debug_str` section. - StringRef(StringId), - - /// A reference to a string in the `.debug_line_str` section. - LineStringRef(LineStringId), -} - -impl LineString { - /// Create a `LineString` using the normal form for the given encoding. - pub fn new<T>(val: T, encoding: Encoding, line_strings: &mut LineStringTable) -> Self - where - T: Into<Vec<u8>>, - { - let val = val.into(); - if encoding.version <= 4 { - LineString::String(val) - } else { - LineString::LineStringRef(line_strings.add(val)) - } - } - - fn form(&self) -> constants::DwForm { - match *self { - LineString::String(..) => constants::DW_FORM_string, - LineString::StringRef(..) => constants::DW_FORM_strp, - LineString::LineStringRef(..) => constants::DW_FORM_line_strp, - } - } - - fn write<W: Writer>( - &self, - w: &mut DebugLine<W>, - form: constants::DwForm, - encoding: Encoding, - debug_line_str_offsets: &DebugLineStrOffsets, - debug_str_offsets: &DebugStrOffsets, - ) -> Result<()> { - if form != self.form() { - return Err(Error::LineStringFormMismatch); - } - - match *self { - LineString::String(ref val) => { - if encoding.version <= 4 { - debug_assert!(!val.is_empty()); - } - w.write(val)?; - w.write_u8(0)?; - } - LineString::StringRef(val) => { - if encoding.version < 5 { - return Err(Error::NeedVersion(5)); - } - w.write_offset( - debug_str_offsets.get(val).0, - SectionId::DebugStr, - encoding.format.word_size(), - )?; - } - LineString::LineStringRef(val) => { - if encoding.version < 5 { - return Err(Error::NeedVersion(5)); - } - w.write_offset( - debug_line_str_offsets.get(val).0, - SectionId::DebugLineStr, - encoding.format.word_size(), - )?; - } - } - Ok(()) - } -} - -/// An identifier for a directory in a `LineProgram`. -/// -/// Defaults to the working directory of the compilation unit. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DirectoryId(usize); - -// Force FileId access via the methods. -mod id { - /// An identifier for a file in a `LineProgram`. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub struct FileId(usize); - - impl FileId { - /// Create a FileId given an index into `LineProgram::files`. - pub(crate) fn new(index: usize) -> Self { - FileId(index + 1) - } - - /// The index of the file in `LineProgram::files`. - pub(super) fn index(self) -> Option<usize> { - if self.0 == 0 { - None - } else { - Some(self.0 - 1) - } - } - - /// The initial state of the file register. - pub(super) fn initial_state() -> Self { - FileId(1) - } - - /// The raw value used when writing. - pub(crate) fn raw(self) -> u64 { - self.0 as u64 - } - - /// The id for file index 0 in DWARF version 5. - /// Only used when converting. - // Used for tests only. - #[allow(unused)] - pub(super) fn zero() -> Self { - FileId(0) - } - } -} -pub use self::id::*; - -/// Extra information for file in a `LineProgram`. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -pub struct FileInfo { - /// The implementation defined timestamp of the last modification of the file, - /// or 0 if not available. - pub timestamp: u64, - - /// The size of the file in bytes, or 0 if not available. - pub size: u64, - - /// A 16-byte MD5 digest of the file contents. - /// - /// Only used if version >= 5 and `LineProgram::file_has_md5` is `true`. - pub md5: [u8; 16], -} - -define_section!( - DebugLine, - DebugLineOffset, - "A writable `.debug_line` section." -); - -#[cfg(feature = "read")] -mod convert { - use super::*; - use crate::read::{self, Reader}; - use crate::write::{self, ConvertError, ConvertResult}; - - impl LineProgram { - /// Create a line number program by reading the data from the given program. - /// - /// Return the program and a mapping from file index to `FileId`. - pub fn from<R: Reader<Offset = usize>>( - mut from_program: read::IncompleteLineProgram<R>, - dwarf: &read::Dwarf<R>, - line_strings: &mut write::LineStringTable, - strings: &mut write::StringTable, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<(LineProgram, Vec<FileId>)> { - // Create mappings in case the source has duplicate files or directories. - let mut dirs = Vec::new(); - let mut files = Vec::new(); - - let mut program = { - let from_header = from_program.header(); - let encoding = from_header.encoding(); - - let comp_dir = match from_header.directory(0) { - Some(comp_dir) => LineString::from(comp_dir, dwarf, line_strings, strings)?, - None => LineString::new(&[][..], encoding, line_strings), - }; - - let (comp_name, comp_file_info) = match from_header.file(0) { - Some(comp_file) => { - if comp_file.directory_index() != 0 { - return Err(ConvertError::InvalidDirectoryIndex); - } - ( - LineString::from(comp_file.path_name(), dwarf, line_strings, strings)?, - Some(FileInfo { - timestamp: comp_file.timestamp(), - size: comp_file.size(), - md5: *comp_file.md5(), - }), - ) - } - None => (LineString::new(&[][..], encoding, line_strings), None), - }; - - if from_header.line_base() > 0 { - return Err(ConvertError::InvalidLineBase); - } - let mut program = LineProgram::new( - encoding, - from_header.line_encoding(), - comp_dir, - comp_name, - comp_file_info, - ); - - let file_skip; - if from_header.version() <= 4 { - // The first directory is implicit. - dirs.push(DirectoryId(0)); - // A file index of 0 is invalid for version <= 4, but putting - // something there makes the indexing easier. - file_skip = 0; - files.push(FileId::zero()); - } else { - // We don't add the first file to `files`, but still allow - // it to be referenced from converted instructions. - file_skip = 1; - files.push(FileId::zero()); - } - - for from_dir in from_header.include_directories() { - let from_dir = - LineString::from(from_dir.clone(), dwarf, line_strings, strings)?; - dirs.push(program.add_directory(from_dir)); - } - - program.file_has_timestamp = from_header.file_has_timestamp(); - program.file_has_size = from_header.file_has_size(); - program.file_has_md5 = from_header.file_has_md5(); - for from_file in from_header.file_names().iter().skip(file_skip) { - let from_name = - LineString::from(from_file.path_name(), dwarf, line_strings, strings)?; - let from_dir = from_file.directory_index(); - if from_dir >= dirs.len() as u64 { - return Err(ConvertError::InvalidDirectoryIndex); - } - let from_dir = dirs[from_dir as usize]; - let from_info = Some(FileInfo { - timestamp: from_file.timestamp(), - size: from_file.size(), - md5: *from_file.md5(), - }); - files.push(program.add_file(from_name, from_dir, from_info)); - } - - program - }; - - // We can't use the `from_program.rows()` because that wouldn't let - // us preserve address relocations. - let mut from_row = read::LineRow::new(from_program.header()); - let mut instructions = from_program.header().instructions(); - let mut address = None; - while let Some(instruction) = instructions.next_instruction(from_program.header())? { - match instruction { - read::LineInstruction::SetAddress(val) => { - if program.in_sequence() { - return Err(ConvertError::UnsupportedLineInstruction); - } - match convert_address(val) { - Some(val) => address = Some(val), - None => return Err(ConvertError::InvalidAddress), - } - from_row.execute(read::LineInstruction::SetAddress(0), &mut from_program); - } - read::LineInstruction::DefineFile(_) => { - return Err(ConvertError::UnsupportedLineInstruction); - } - _ => { - if from_row.execute(instruction, &mut from_program) { - if !program.in_sequence() { - program.begin_sequence(address); - address = None; - } - if from_row.end_sequence() { - program.end_sequence(from_row.address()); - } else { - program.row().address_offset = from_row.address(); - program.row().op_index = from_row.op_index(); - program.row().file = { - let file = from_row.file_index(); - if file >= files.len() as u64 { - return Err(ConvertError::InvalidFileIndex); - } - if file == 0 && program.version() <= 4 { - return Err(ConvertError::InvalidFileIndex); - } - files[file as usize] - }; - program.row().line = match from_row.line() { - Some(line) => line.get(), - None => 0, - }; - program.row().column = match from_row.column() { - read::ColumnType::LeftEdge => 0, - read::ColumnType::Column(val) => val.get(), - }; - program.row().discriminator = from_row.discriminator(); - program.row().is_statement = from_row.is_stmt(); - program.row().basic_block = from_row.basic_block(); - program.row().prologue_end = from_row.prologue_end(); - program.row().epilogue_begin = from_row.epilogue_begin(); - program.row().isa = from_row.isa(); - program.generate_row(); - } - from_row.reset(from_program.header()); - } - } - }; - } - Ok((program, files)) - } - } - - impl LineString { - fn from<R: Reader<Offset = usize>>( - from_attr: read::AttributeValue<R>, - dwarf: &read::Dwarf<R>, - line_strings: &mut write::LineStringTable, - strings: &mut write::StringTable, - ) -> ConvertResult<LineString> { - Ok(match from_attr { - read::AttributeValue::String(r) => LineString::String(r.to_slice()?.to_vec()), - read::AttributeValue::DebugStrRef(offset) => { - let r = dwarf.debug_str.get_str(offset)?; - let id = strings.add(r.to_slice()?); - LineString::StringRef(id) - } - read::AttributeValue::DebugLineStrRef(offset) => { - let r = dwarf.debug_line_str.get_str(offset)?; - let id = line_strings.add(r.to_slice()?); - LineString::LineStringRef(id) - } - _ => return Err(ConvertError::UnsupportedLineStringForm), - }) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::read; - use crate::write::{DebugLineStr, DebugStr, EndianVec, StringTable}; - use crate::LittleEndian; - - #[test] - fn test_line_program_table() { - let dir1 = LineString::String(b"dir1".to_vec()); - let file1 = LineString::String(b"file1".to_vec()); - let dir2 = LineString::String(b"dir2".to_vec()); - let file2 = LineString::String(b"file2".to_vec()); - - let mut programs = Vec::new(); - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let mut program = LineProgram::new( - encoding, - LineEncoding::default(), - dir1.clone(), - file1.clone(), - None, - ); - - { - assert_eq!(&dir1, program.get_directory(program.default_directory())); - program.file_has_timestamp = true; - program.file_has_size = true; - if encoding.version >= 5 { - program.file_has_md5 = true; - } - - let dir_id = program.add_directory(dir2.clone()); - assert_eq!(&dir2, program.get_directory(dir_id)); - assert_eq!(dir_id, program.add_directory(dir2.clone())); - - let file_info = FileInfo { - timestamp: 1, - size: 2, - md5: if encoding.version >= 5 { - [3; 16] - } else { - [0; 16] - }, - }; - let file_id = program.add_file(file2.clone(), dir_id, Some(file_info)); - assert_eq!((&file2, dir_id), program.get_file(file_id)); - assert_eq!(file_info, *program.get_file_info(file_id)); - - program.get_file_info_mut(file_id).size = 3; - assert_ne!(file_info, *program.get_file_info(file_id)); - assert_eq!(file_id, program.add_file(file2.clone(), dir_id, None)); - assert_ne!(file_info, *program.get_file_info(file_id)); - assert_eq!( - file_id, - program.add_file(file2.clone(), dir_id, Some(file_info)) - ); - assert_eq!(file_info, *program.get_file_info(file_id)); - - programs.push((program, file_id, encoding)); - } - } - } - } - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let mut debug_line_offsets = Vec::new(); - for (program, _, encoding) in &programs { - debug_line_offsets.push( - program - .write( - &mut debug_line, - *encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(), - ); - } - - let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); - - let convert_address = &|address| Some(Address::Constant(address)); - for ((program, file_id, encoding), offset) in programs.iter().zip(debug_line_offsets.iter()) - { - let read_program = read_debug_line - .program( - *offset, - encoding.address_size, - Some(read::EndianSlice::new(b"dir1", LittleEndian)), - Some(read::EndianSlice::new(b"file1", LittleEndian)), - ) - .unwrap(); - - let dwarf = read::Dwarf::default(); - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let (convert_program, convert_files) = LineProgram::from( - read_program, - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - convert_address, - ) - .unwrap(); - assert_eq!(convert_program.version(), program.version()); - assert_eq!(convert_program.address_size(), program.address_size()); - assert_eq!(convert_program.format(), program.format()); - - let convert_file_id = convert_files[file_id.raw() as usize]; - let (file, dir) = program.get_file(*file_id); - let (convert_file, convert_dir) = convert_program.get_file(convert_file_id); - assert_eq!(file, convert_file); - assert_eq!( - program.get_directory(dir), - convert_program.get_directory(convert_dir) - ); - assert_eq!( - program.get_file_info(*file_id), - convert_program.get_file_info(convert_file_id) - ); - } - } - - #[test] - fn test_line_row() { - let dir1 = &b"dir1"[..]; - let file1 = &b"file1"[..]; - let file2 = &b"file2"[..]; - let convert_address = &|address| Some(Address::Constant(address)); - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let line_base = -5; - let line_range = 14; - let neg_line_base = (-line_base) as u8; - let mut program = LineProgram::new( - encoding, - LineEncoding { - line_base, - line_range, - ..Default::default() - }, - LineString::String(dir1.to_vec()), - LineString::String(file1.to_vec()), - None, - ); - let dir_id = program.default_directory(); - program.add_file(LineString::String(file1.to_vec()), dir_id, None); - let file_id = - program.add_file(LineString::String(file2.to_vec()), dir_id, None); - - // Test sequences. - { - let mut program = program.clone(); - let address = Address::Constant(0x12); - program.begin_sequence(Some(address)); - assert_eq!( - program.instructions, - vec![LineInstruction::SetAddress(address)] - ); - } - - { - let mut program = program.clone(); - program.begin_sequence(None); - assert_eq!(program.instructions, Vec::new()); - } - - { - let mut program = program.clone(); - program.begin_sequence(None); - program.end_sequence(0x1234); - assert_eq!( - program.instructions, - vec![ - LineInstruction::AdvancePc(0x1234), - LineInstruction::EndSequence - ] - ); - } - - // Create a base program. - program.begin_sequence(None); - program.row.line = 0x1000; - program.generate_row(); - let base_row = program.row; - let base_instructions = program.instructions.clone(); - - // Create test cases. - let mut tests = Vec::new(); - - let row = base_row; - tests.push((row, vec![LineInstruction::Copy])); - - let mut row = base_row; - row.line -= u64::from(neg_line_base); - tests.push((row, vec![LineInstruction::Special(OPCODE_BASE)])); - - let mut row = base_row; - row.line += u64::from(line_range) - 1; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::Special(OPCODE_BASE + line_range - 1)], - )); - - let mut row = base_row; - row.line += u64::from(line_range); - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![ - LineInstruction::AdvanceLine(i64::from(line_range - neg_line_base)), - LineInstruction::Copy, - ], - )); - - let mut row = base_row; - row.address_offset = 1; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::Special(OPCODE_BASE + line_range)], - )); - - let op_range = (255 - OPCODE_BASE) / line_range; - let mut row = base_row; - row.address_offset = u64::from(op_range); - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::Special( - OPCODE_BASE + op_range * line_range, - )], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range); - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range); - row.line -= u64::from(neg_line_base); - tests.push((row, vec![LineInstruction::Special(255)])); - - let mut row = base_row; - row.address_offset = u64::from(op_range); - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::ConstAddPc, LineInstruction::Copy], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range); - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![ - LineInstruction::ConstAddPc, - LineInstruction::Special(OPCODE_BASE + 6), - ], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range) * 2; - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range); - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![LineInstruction::ConstAddPc, LineInstruction::Special(255)], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range) * 2; - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![ - LineInstruction::AdvancePc(row.address_offset), - LineInstruction::Copy, - ], - )); - - let mut row = base_row; - row.address_offset = u64::from(op_range) * 2; - row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2; - row.line -= u64::from(neg_line_base); - tests.push(( - row, - vec![ - LineInstruction::AdvancePc(row.address_offset), - LineInstruction::Special(OPCODE_BASE + 6), - ], - )); - - let mut row = base_row; - row.address_offset = 0x1234; - tests.push(( - row, - vec![LineInstruction::AdvancePc(0x1234), LineInstruction::Copy], - )); - - let mut row = base_row; - row.line += 0x1234; - tests.push(( - row, - vec![LineInstruction::AdvanceLine(0x1234), LineInstruction::Copy], - )); - - let mut row = base_row; - row.file = file_id; - tests.push(( - row, - vec![LineInstruction::SetFile(file_id), LineInstruction::Copy], - )); - - let mut row = base_row; - row.column = 0x1234; - tests.push(( - row, - vec![LineInstruction::SetColumn(0x1234), LineInstruction::Copy], - )); - - let mut row = base_row; - row.discriminator = 0x1234; - tests.push(( - row, - vec![ - LineInstruction::SetDiscriminator(0x1234), - LineInstruction::Copy, - ], - )); - - let mut row = base_row; - row.is_statement = !row.is_statement; - tests.push(( - row, - vec![LineInstruction::NegateStatement, LineInstruction::Copy], - )); - - let mut row = base_row; - row.basic_block = true; - tests.push(( - row, - vec![LineInstruction::SetBasicBlock, LineInstruction::Copy], - )); - - let mut row = base_row; - row.prologue_end = true; - tests.push(( - row, - vec![LineInstruction::SetPrologueEnd, LineInstruction::Copy], - )); - - let mut row = base_row; - row.epilogue_begin = true; - tests.push(( - row, - vec![LineInstruction::SetEpilogueBegin, LineInstruction::Copy], - )); - - let mut row = base_row; - row.isa = 0x1234; - tests.push(( - row, - vec![LineInstruction::SetIsa(0x1234), LineInstruction::Copy], - )); - - for test in tests { - // Test generate_row(). - let mut program = program.clone(); - program.row = test.0; - program.generate_row(); - assert_eq!( - &program.instructions[base_instructions.len()..], - &test.1[..] - ); - - // Test LineProgram::from(). - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = - read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program( - debug_line_offset, - address_size, - Some(read::EndianSlice::new(dir1, LittleEndian)), - Some(read::EndianSlice::new(file1, LittleEndian)), - ) - .unwrap(); - - let dwarf = read::Dwarf::default(); - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let (convert_program, _convert_files) = LineProgram::from( - read_program, - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - convert_address, - ) - .unwrap(); - assert_eq!( - &convert_program.instructions[base_instructions.len()..], - &test.1[..] - ); - } - } - } - } - } - - #[test] - fn test_line_instruction() { - let dir1 = &b"dir1"[..]; - let file1 = &b"file1"[..]; - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let mut program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(dir1.to_vec()), - LineString::String(file1.to_vec()), - None, - ); - let dir_id = program.default_directory(); - let file_id = - program.add_file(LineString::String(file1.to_vec()), dir_id, None); - - for &(ref inst, ref expect_inst) in &[ - ( - LineInstruction::Special(OPCODE_BASE), - read::LineInstruction::Special(OPCODE_BASE), - ), - ( - LineInstruction::Special(255), - read::LineInstruction::Special(255), - ), - (LineInstruction::Copy, read::LineInstruction::Copy), - ( - LineInstruction::AdvancePc(0x12), - read::LineInstruction::AdvancePc(0x12), - ), - ( - LineInstruction::AdvanceLine(0x12), - read::LineInstruction::AdvanceLine(0x12), - ), - ( - LineInstruction::SetFile(file_id), - read::LineInstruction::SetFile(file_id.raw()), - ), - ( - LineInstruction::SetColumn(0x12), - read::LineInstruction::SetColumn(0x12), - ), - ( - LineInstruction::NegateStatement, - read::LineInstruction::NegateStatement, - ), - ( - LineInstruction::SetBasicBlock, - read::LineInstruction::SetBasicBlock, - ), - ( - LineInstruction::ConstAddPc, - read::LineInstruction::ConstAddPc, - ), - ( - LineInstruction::SetPrologueEnd, - read::LineInstruction::SetPrologueEnd, - ), - ( - LineInstruction::SetEpilogueBegin, - read::LineInstruction::SetEpilogueBegin, - ), - ( - LineInstruction::SetIsa(0x12), - read::LineInstruction::SetIsa(0x12), - ), - ( - LineInstruction::EndSequence, - read::LineInstruction::EndSequence, - ), - ( - LineInstruction::SetAddress(Address::Constant(0x12)), - read::LineInstruction::SetAddress(0x12), - ), - ( - LineInstruction::SetDiscriminator(0x12), - read::LineInstruction::SetDiscriminator(0x12), - ), - ][..] - { - let mut program = program.clone(); - program.instructions.push(*inst); - - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = - read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program( - debug_line_offset, - address_size, - Some(read::EndianSlice::new(dir1, LittleEndian)), - Some(read::EndianSlice::new(file1, LittleEndian)), - ) - .unwrap(); - let read_header = read_program.header(); - let mut read_insts = read_header.instructions(); - assert_eq!( - *expect_inst, - read_insts.next_instruction(read_header).unwrap().unwrap() - ); - assert_eq!(None, read_insts.next_instruction(read_header).unwrap()); - } - } - } - } - } - - // Test that the address/line advance is correct. We don't test for optimality. - #[test] - fn test_advance() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - - let dir1 = &b"dir1"[..]; - let file1 = &b"file1"[..]; - - let addresses = 0..50; - let lines = -10..25i64; - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - - for minimum_instruction_length in vec![1, 4] { - for maximum_operations_per_instruction in vec![1, 3] { - for line_base in vec![-5, 0] { - for line_range in vec![10, 20] { - let line_encoding = LineEncoding { - minimum_instruction_length, - maximum_operations_per_instruction, - line_base, - line_range, - default_is_stmt: true, - }; - let mut program = LineProgram::new( - encoding, - line_encoding, - LineString::String(dir1.to_vec()), - LineString::String(file1.to_vec()), - None, - ); - for address_advance in addresses.clone() { - program.begin_sequence(Some(Address::Constant(0x1000))); - program.row().line = 0x10000; - program.generate_row(); - for line_advance in lines.clone() { - { - let row = program.row(); - row.address_offset += - address_advance * u64::from(minimum_instruction_length); - row.line = row.line.wrapping_add(line_advance as u64); - } - program.generate_row(); - } - let address_offset = program.row().address_offset - + u64::from(minimum_instruction_length); - program.end_sequence(address_offset); - } - - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = - read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program( - debug_line_offset, - 8, - Some(read::EndianSlice::new(dir1, LittleEndian)), - Some(read::EndianSlice::new(file1, LittleEndian)), - ) - .unwrap(); - - let mut rows = read_program.rows(); - for address_advance in addresses.clone() { - let mut address; - let mut line; - { - let row = rows.next_row().unwrap().unwrap().1; - address = row.address(); - line = row.line().unwrap().get(); - } - assert_eq!(address, 0x1000); - assert_eq!(line, 0x10000); - for line_advance in lines.clone() { - let row = rows.next_row().unwrap().unwrap().1; - assert_eq!( - row.address() - address, - address_advance * u64::from(minimum_instruction_length) - ); - assert_eq!( - (row.line().unwrap().get() as i64) - (line as i64), - line_advance - ); - address = row.address(); - line = row.line().unwrap().get(); - } - let row = rows.next_row().unwrap().unwrap().1; - assert!(row.end_sequence()); - } - } - } - } - } - } - - #[test] - fn test_line_string() { - let version = 5; - - let file = b"file1"; - - let mut strings = StringTable::default(); - let string_id = strings.add("file2"); - let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); - let debug_str_offsets = strings.write(&mut debug_str).unwrap(); - - let mut line_strings = LineStringTable::default(); - let line_string_id = line_strings.add("file3"); - let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian)); - let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap(); - - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - for (file, expect_file) in vec![ - ( - LineString::String(file.to_vec()), - read::AttributeValue::String(read::EndianSlice::new(file, LittleEndian)), - ), - ( - LineString::StringRef(string_id), - read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)), - ), - ( - LineString::LineStringRef(line_string_id), - read::AttributeValue::DebugLineStrRef( - debug_line_str_offsets.get(line_string_id), - ), - ), - ] { - let program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(b"dir".to_vec()), - file, - None, - ); - - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program(debug_line_offset, address_size, None, None) - .unwrap(); - let read_header = read_program.header(); - assert_eq!(read_header.file(0).unwrap().path_name(), expect_file); - } - } - } - } - - #[test] - fn test_missing_comp_dir() { - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - let program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(Vec::new()), - LineString::String(Vec::new()), - None, - ); - - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let debug_line_offset = program - .write( - &mut debug_line, - encoding, - &debug_line_str_offsets, - &debug_str_offsets, - ) - .unwrap(); - - let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_program = read_debug_line - .program( - debug_line_offset, - address_size, - // Testing missing comp_dir/comp_name. - None, - None, - ) - .unwrap(); - - let dwarf = read::Dwarf::default(); - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let convert_address = &|address| Some(Address::Constant(address)); - LineProgram::from( - read_program, - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - convert_address, - ) - .unwrap(); - } - } - } - } -} diff --git a/vendor/gimli/src/write/loc.rs b/vendor/gimli/src/write/loc.rs deleted file mode 100644 index 6dfe45a..0000000 --- a/vendor/gimli/src/write/loc.rs +++ /dev/null @@ -1,550 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{Encoding, LocationListsOffset, SectionId}; -use crate::write::{ - Address, BaseId, DebugInfoReference, Error, Expression, Result, Section, Sections, UnitOffsets, - Writer, -}; - -define_section!( - DebugLoc, - LocationListsOffset, - "A writable `.debug_loc` section." -); -define_section!( - DebugLocLists, - LocationListsOffset, - "A writable `.debug_loclists` section." -); - -define_offsets!( - LocationListOffsets: LocationListId => LocationListsOffset, - "The section offsets of a series of location lists within the `.debug_loc` or `.debug_loclists` sections." -); - -define_id!( - LocationListId, - "An identifier for a location list in a `LocationListTable`." -); - -/// A table of location lists that will be stored in a `.debug_loc` or `.debug_loclists` section. -#[derive(Debug, Default)] -pub struct LocationListTable { - base_id: BaseId, - locations: IndexSet<LocationList>, -} - -impl LocationListTable { - /// Add a location list to the table. - pub fn add(&mut self, loc_list: LocationList) -> LocationListId { - let (index, _) = self.locations.insert_full(loc_list); - LocationListId::new(self.base_id, index) - } - - /// Write the location list table to the appropriate section for the given DWARF version. - pub(crate) fn write<W: Writer>( - &self, - sections: &mut Sections<W>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - ) -> Result<LocationListOffsets> { - if self.locations.is_empty() { - return Ok(LocationListOffsets::none()); - } - - match encoding.version { - 2..=4 => self.write_loc( - &mut sections.debug_loc, - &mut sections.debug_loc_refs, - encoding, - unit_offsets, - ), - 5 => self.write_loclists( - &mut sections.debug_loclists, - &mut sections.debug_loclists_refs, - encoding, - unit_offsets, - ), - _ => Err(Error::UnsupportedVersion(encoding.version)), - } - } - - /// Write the location list table to the `.debug_loc` section. - fn write_loc<W: Writer>( - &self, - w: &mut DebugLoc<W>, - refs: &mut Vec<DebugInfoReference>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - ) -> Result<LocationListOffsets> { - let address_size = encoding.address_size; - let mut offsets = Vec::new(); - for loc_list in self.locations.iter() { - offsets.push(w.offset()); - for loc in &loc_list.0 { - // Note that we must ensure none of the ranges have both begin == 0 and end == 0. - // We do this by ensuring that begin != end, which is a bit more restrictive - // than required, but still seems reasonable. - match *loc { - Location::BaseAddress { address } => { - let marker = !0 >> (64 - address_size * 8); - w.write_udata(marker, address_size)?; - w.write_address(address, address_size)?; - } - Location::OffsetPair { - begin, - end, - ref data, - } => { - if begin == end { - return Err(Error::InvalidRange); - } - w.write_udata(begin, address_size)?; - w.write_udata(end, address_size)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::StartEnd { - begin, - end, - ref data, - } => { - if begin == end { - return Err(Error::InvalidRange); - } - w.write_address(begin, address_size)?; - w.write_address(end, address_size)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::StartLength { - begin, - length, - ref data, - } => { - let end = match begin { - Address::Constant(begin) => Address::Constant(begin + length), - Address::Symbol { symbol, addend } => Address::Symbol { - symbol, - addend: addend + length as i64, - }, - }; - if begin == end { - return Err(Error::InvalidRange); - } - w.write_address(begin, address_size)?; - w.write_address(end, address_size)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::DefaultLocation { .. } => { - return Err(Error::InvalidRange); - } - } - } - w.write_udata(0, address_size)?; - w.write_udata(0, address_size)?; - } - Ok(LocationListOffsets { - base_id: self.base_id, - offsets, - }) - } - - /// Write the location list table to the `.debug_loclists` section. - fn write_loclists<W: Writer>( - &self, - w: &mut DebugLocLists<W>, - refs: &mut Vec<DebugInfoReference>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - ) -> Result<LocationListOffsets> { - let mut offsets = Vec::new(); - - if encoding.version != 5 { - return Err(Error::NeedVersion(5)); - } - - let length_offset = w.write_initial_length(encoding.format)?; - let length_base = w.len(); - - w.write_u16(encoding.version)?; - w.write_u8(encoding.address_size)?; - w.write_u8(0)?; // segment_selector_size - w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) - // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list - - for loc_list in self.locations.iter() { - offsets.push(w.offset()); - for loc in &loc_list.0 { - match *loc { - Location::BaseAddress { address } => { - w.write_u8(crate::constants::DW_LLE_base_address.0)?; - w.write_address(address, encoding.address_size)?; - } - Location::OffsetPair { - begin, - end, - ref data, - } => { - w.write_u8(crate::constants::DW_LLE_offset_pair.0)?; - w.write_uleb128(begin)?; - w.write_uleb128(end)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::StartEnd { - begin, - end, - ref data, - } => { - w.write_u8(crate::constants::DW_LLE_start_end.0)?; - w.write_address(begin, encoding.address_size)?; - w.write_address(end, encoding.address_size)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::StartLength { - begin, - length, - ref data, - } => { - w.write_u8(crate::constants::DW_LLE_start_length.0)?; - w.write_address(begin, encoding.address_size)?; - w.write_uleb128(length)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - Location::DefaultLocation { ref data } => { - w.write_u8(crate::constants::DW_LLE_default_location.0)?; - write_expression(&mut w.0, refs, encoding, unit_offsets, data)?; - } - } - } - - w.write_u8(crate::constants::DW_LLE_end_of_list.0)?; - } - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, encoding.format)?; - - Ok(LocationListOffsets { - base_id: self.base_id, - offsets, - }) - } -} - -/// A locations list that will be stored in a `.debug_loc` or `.debug_loclists` section. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct LocationList(pub Vec<Location>); - -/// A single location. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum Location { - /// DW_LLE_base_address - BaseAddress { - /// Base address. - address: Address, - }, - /// DW_LLE_offset_pair - OffsetPair { - /// Start of range relative to base address. - begin: u64, - /// End of range relative to base address. - end: u64, - /// Location description. - data: Expression, - }, - /// DW_LLE_start_end - StartEnd { - /// Start of range. - begin: Address, - /// End of range. - end: Address, - /// Location description. - data: Expression, - }, - /// DW_LLE_start_length - StartLength { - /// Start of range. - begin: Address, - /// Length of range. - length: u64, - /// Location description. - data: Expression, - }, - /// DW_LLE_default_location - DefaultLocation { - /// Location description. - data: Expression, - }, -} - -fn write_expression<W: Writer>( - w: &mut W, - refs: &mut Vec<DebugInfoReference>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - val: &Expression, -) -> Result<()> { - let size = val.size(encoding, unit_offsets) as u64; - if encoding.version <= 4 { - w.write_udata(size, 2)?; - } else { - w.write_uleb128(size)?; - } - val.write(w, Some(refs), encoding, unit_offsets)?; - Ok(()) -} - -#[cfg(feature = "read")] -mod convert { - use super::*; - - use crate::read::{self, Reader}; - use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; - - impl LocationList { - /// Create a location list by reading the data from the give location list iter. - pub(crate) fn from<R: Reader<Offset = usize>>( - mut from: read::RawLocListIter<R>, - context: &ConvertUnitContext<R>, - ) -> ConvertResult<Self> { - let mut have_base_address = context.base_address != Address::Constant(0); - let convert_address = - |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); - let convert_expression = |x| { - Expression::from( - x, - context.unit.encoding(), - Some(context.dwarf), - Some(context.unit), - Some(context.entry_ids), - context.convert_address, - ) - }; - let mut loc_list = Vec::new(); - while let Some(from_loc) = from.next()? { - let loc = match from_loc { - read::RawLocListEntry::AddressOrOffsetPair { begin, end, data } => { - // These were parsed as addresses, even if they are offsets. - let begin = convert_address(begin)?; - let end = convert_address(end)?; - let data = convert_expression(data)?; - match (begin, end) { - (Address::Constant(begin_offset), Address::Constant(end_offset)) => { - if have_base_address { - Location::OffsetPair { - begin: begin_offset, - end: end_offset, - data, - } - } else { - Location::StartEnd { begin, end, data } - } - } - _ => { - if have_base_address { - // At least one of begin/end is an address, but we also have - // a base address. Adding addresses is undefined. - return Err(ConvertError::InvalidRangeRelativeAddress); - } - Location::StartEnd { begin, end, data } - } - } - } - read::RawLocListEntry::BaseAddress { addr } => { - have_base_address = true; - let address = convert_address(addr)?; - Location::BaseAddress { address } - } - read::RawLocListEntry::BaseAddressx { addr } => { - have_base_address = true; - let address = convert_address(context.dwarf.address(context.unit, addr)?)?; - Location::BaseAddress { address } - } - read::RawLocListEntry::StartxEndx { begin, end, data } => { - let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; - let end = convert_address(context.dwarf.address(context.unit, end)?)?; - let data = convert_expression(data)?; - Location::StartEnd { begin, end, data } - } - read::RawLocListEntry::StartxLength { - begin, - length, - data, - } => { - let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; - let data = convert_expression(data)?; - Location::StartLength { - begin, - length, - data, - } - } - read::RawLocListEntry::OffsetPair { begin, end, data } => { - let data = convert_expression(data)?; - Location::OffsetPair { begin, end, data } - } - read::RawLocListEntry::StartEnd { begin, end, data } => { - let begin = convert_address(begin)?; - let end = convert_address(end)?; - let data = convert_expression(data)?; - Location::StartEnd { begin, end, data } - } - read::RawLocListEntry::StartLength { - begin, - length, - data, - } => { - let begin = convert_address(begin)?; - let data = convert_expression(data)?; - Location::StartLength { - begin, - length, - data, - } - } - read::RawLocListEntry::DefaultLocation { data } => { - let data = convert_expression(data)?; - Location::DefaultLocation { data } - } - }; - // In some cases, existing data may contain begin == end, filtering - // these out. - match loc { - Location::StartLength { length, .. } if length == 0 => continue, - Location::StartEnd { begin, end, .. } if begin == end => continue, - Location::OffsetPair { begin, end, .. } if begin == end => continue, - _ => (), - } - loc_list.push(loc); - } - Ok(LocationList(loc_list)) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::common::{ - DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, - }; - use crate::read; - use crate::write::{ - ConvertUnitContext, EndianVec, LineStringTable, RangeListTable, StringTable, - }; - use crate::LittleEndian; - use std::collections::HashMap; - use std::sync::Arc; - - #[test] - fn test_loc_list() { - let mut line_strings = LineStringTable::default(); - let mut strings = StringTable::default(); - let mut expression = Expression::new(); - expression.op_constu(0); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - let mut loc_list = LocationList(vec![ - Location::StartLength { - begin: Address::Constant(6666), - length: 7777, - data: expression.clone(), - }, - Location::StartEnd { - begin: Address::Constant(4444), - end: Address::Constant(5555), - data: expression.clone(), - }, - Location::BaseAddress { - address: Address::Constant(1111), - }, - Location::OffsetPair { - begin: 2222, - end: 3333, - data: expression.clone(), - }, - ]); - if version >= 5 { - loc_list.0.push(Location::DefaultLocation { - data: expression.clone(), - }); - } - - let mut locations = LocationListTable::default(); - let loc_list_id = locations.add(loc_list.clone()); - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap(); - assert!(sections.debug_loc_refs.is_empty()); - assert!(sections.debug_loclists_refs.is_empty()); - - let read_debug_loc = - read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian); - let read_debug_loclists = - read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian); - let read_loc = read::LocationLists::new(read_debug_loc, read_debug_loclists); - let offset = loc_list_offsets.get(loc_list_id); - let read_loc_list = read_loc.raw_locations(offset, encoding).unwrap(); - - let dwarf = read::Dwarf { - locations: read_loc, - ..Default::default() - }; - let unit = read::Unit { - header: read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::default(), - ), - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - let context = ConvertUnitContext { - dwarf: &dwarf, - unit: &unit, - line_strings: &mut line_strings, - strings: &mut strings, - ranges: &mut RangeListTable::default(), - locations: &mut locations, - convert_address: &|address| Some(Address::Constant(address)), - base_address: Address::Constant(0), - line_program_offset: None, - line_program_files: Vec::new(), - entry_ids: &HashMap::new(), - }; - let convert_loc_list = LocationList::from(read_loc_list, &context).unwrap(); - - if version <= 4 { - loc_list.0[0] = Location::StartEnd { - begin: Address::Constant(6666), - end: Address::Constant(6666 + 7777), - data: expression.clone(), - }; - } - assert_eq!(loc_list, convert_loc_list); - } - } - } - } -} diff --git a/vendor/gimli/src/write/mod.rs b/vendor/gimli/src/write/mod.rs deleted file mode 100644 index 47ba631..0000000 --- a/vendor/gimli/src/write/mod.rs +++ /dev/null @@ -1,425 +0,0 @@ -//! Write DWARF debugging information. -//! -//! ## API Structure -//! -//! This module works by building up a representation of the debugging information -//! in memory, and then writing it all at once. It supports two major use cases: -//! -//! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF -//! for a single compilation unit. -//! -//! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple -//! compilation units. -//! -//! The module also supports reading in DWARF debugging information and writing it out -//! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html) -//! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert -//! it to a writable instance. -//! -//! ## Example Usage -//! -//! Write a compilation unit containing only the top level DIE. -//! -//! ```rust -//! use gimli::write::{ -//! Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections, -//! }; -//! -//! fn example() -> Result<(), Error> { -//! // Choose the encoding parameters. -//! let encoding = gimli::Encoding { -//! format: gimli::Format::Dwarf32, -//! version: 5, -//! address_size: 8, -//! }; -//! // Create a container for a single compilation unit. -//! let mut dwarf = DwarfUnit::new(encoding); -//! // Set a range attribute on the root DIE. -//! let range_list = RangeList(vec![Range::StartLength { -//! begin: Address::Constant(0x100), -//! length: 42, -//! }]); -//! let range_list_id = dwarf.unit.ranges.add(range_list); -//! let root = dwarf.unit.root(); -//! dwarf.unit.get_mut(root).set( -//! gimli::DW_AT_ranges, -//! AttributeValue::RangeListRef(range_list_id), -//! ); -//! // Create a `Vec` for each DWARF section. -//! let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian)); -//! // Finally, write the DWARF data to the sections. -//! dwarf.write(&mut sections)?; -//! sections.for_each(|id, data| { -//! // Here you can add the data to the output object file. -//! Ok(()) -//! }) -//! } -//! # fn main() { -//! # example().unwrap(); -//! # } - -use std::error; -use std::fmt; -use std::result; - -use crate::constants; - -mod endian_vec; -pub use self::endian_vec::*; - -mod writer; -pub use self::writer::*; - -#[macro_use] -mod section; -pub use self::section::*; - -macro_rules! define_id { - ($name:ident, $docs:expr) => { - #[doc=$docs] - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub struct $name { - base_id: BaseId, - index: usize, - } - - impl $name { - #[inline] - fn new(base_id: BaseId, index: usize) -> Self { - $name { base_id, index } - } - } - }; -} - -macro_rules! define_offsets { - ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => { - #[doc=$off_doc] - #[derive(Debug)] - pub struct $offsets { - base_id: BaseId, - // We know ids start at 0. - offsets: Vec<$offset>, - } - - impl $offsets { - /// Return an empty list of offsets. - #[inline] - pub fn none() -> Self { - $offsets { - base_id: BaseId::default(), - offsets: Vec::new(), - } - } - - /// Get the offset - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get(&self, id: $id) -> $offset { - debug_assert_eq!(self.base_id, id.base_id); - self.offsets[id.index] - } - - /// Return the number of offsets. - #[inline] - pub fn count(&self) -> usize { - self.offsets.len() - } - } - }; -} - -mod abbrev; -pub use self::abbrev::*; - -mod cfi; -pub use self::cfi::*; - -mod dwarf; -pub use self::dwarf::*; - -mod line; -pub use self::line::*; - -mod loc; -pub use self::loc::*; - -mod op; -pub use self::op::*; - -mod range; -pub use self::range::*; - -mod str; -pub use self::str::*; - -mod unit; -pub use self::unit::*; - -/// An error that occurred when writing. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Error { - /// The given offset is out of bounds. - OffsetOutOfBounds, - /// The given length is out of bounds. - LengthOutOfBounds, - /// The attribute value is an invalid for writing. - InvalidAttributeValue, - /// The value is too large for the encoding form. - ValueTooLarge, - /// Unsupported word size. - UnsupportedWordSize(u8), - /// Unsupported DWARF version. - UnsupportedVersion(u16), - /// The unit length is too large for the requested DWARF format. - InitialLengthOverflow, - /// The address is invalid. - InvalidAddress, - /// The reference is invalid. - InvalidReference, - /// A requested feature requires a different DWARF version. - NeedVersion(u16), - /// Strings in line number program have mismatched forms. - LineStringFormMismatch, - /// The range is empty or otherwise invalid. - InvalidRange, - /// The line number program encoding is incompatible with the unit encoding. - IncompatibleLineProgramEncoding, - /// Could not encode code offset for a frame instruction. - InvalidFrameCodeOffset(u32), - /// Could not encode data offset for a frame instruction. - InvalidFrameDataOffset(i32), - /// Unsupported eh_frame pointer encoding. - UnsupportedPointerEncoding(constants::DwEhPe), - /// Unsupported reference in CFI expression. - UnsupportedCfiExpressionReference, - /// Unsupported forward reference in expression. - UnsupportedExpressionForwardReference, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { - match *self { - Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."), - Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."), - Error::InvalidAttributeValue => { - write!(f, "The attribute value is an invalid for writing.") - } - Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."), - Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size), - Error::UnsupportedVersion(version) => { - write!(f, "Unsupported DWARF version: {}", version) - } - Error::InitialLengthOverflow => write!( - f, - "The unit length is too large for the requested DWARF format." - ), - Error::InvalidAddress => write!(f, "The address is invalid."), - Error::InvalidReference => write!(f, "The reference is invalid."), - Error::NeedVersion(version) => write!( - f, - "A requested feature requires a DWARF version {}.", - version - ), - Error::LineStringFormMismatch => { - write!(f, "Strings in line number program have mismatched forms.") - } - Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."), - Error::IncompatibleLineProgramEncoding => write!( - f, - "The line number program encoding is incompatible with the unit encoding." - ), - Error::InvalidFrameCodeOffset(offset) => write!( - f, - "Could not encode code offset ({}) for a frame instruction.", - offset, - ), - Error::InvalidFrameDataOffset(offset) => write!( - f, - "Could not encode data offset ({}) for a frame instruction.", - offset, - ), - Error::UnsupportedPointerEncoding(eh_pe) => { - write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe) - } - Error::UnsupportedCfiExpressionReference => { - write!(f, "Unsupported reference in CFI expression.") - } - Error::UnsupportedExpressionForwardReference => { - write!(f, "Unsupported forward reference in expression.") - } - } - } -} - -impl error::Error for Error {} - -/// The result of a write. -pub type Result<T> = result::Result<T, Error>; - -/// An address. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Address { - /// A fixed address that does not require relocation. - Constant(u64), - /// An address that is relative to a symbol which may be relocated. - Symbol { - /// The symbol that the address is relative to. - /// - /// The meaning of this value is decided by the writer, but - /// will typically be an index into a symbol table. - symbol: usize, - /// The offset of the address relative to the symbol. - /// - /// This will typically be used as the addend in a relocation. - addend: i64, - }, -} - -/// A reference to a `.debug_info` entry. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Reference { - /// An external symbol. - /// - /// The meaning of this value is decided by the writer, but - /// will typically be an index into a symbol table. - Symbol(usize), - /// An entry in the same section. - /// - /// This only supports references in units that are emitted together. - Entry(UnitId, UnitEntryId), -} - -// This type is only used in debug assertions. -#[cfg(not(debug_assertions))] -type BaseId = (); - -#[cfg(debug_assertions)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -struct BaseId(usize); - -#[cfg(debug_assertions)] -impl Default for BaseId { - fn default() -> Self { - use std::sync::atomic; - static BASE_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed)) - } -} - -#[cfg(feature = "read")] -mod convert { - use super::*; - use crate::read; - - pub(crate) use super::unit::convert::*; - - /// An error that occurred when converting a read value into a write value. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub enum ConvertError { - /// An error occurred when reading. - Read(read::Error), - /// Writing of this attribute value is not implemented yet. - UnsupportedAttributeValue, - /// This attribute value is an invalid name/form combination. - InvalidAttributeValue, - /// A `.debug_info` reference does not refer to a valid entry. - InvalidDebugInfoOffset, - /// An address could not be converted. - InvalidAddress, - /// Writing this line number instruction is not implemented yet. - UnsupportedLineInstruction, - /// Writing this form of line string is not implemented yet. - UnsupportedLineStringForm, - /// A `.debug_line` file index is invalid. - InvalidFileIndex, - /// A `.debug_line` directory index is invalid. - InvalidDirectoryIndex, - /// A `.debug_line` line base is invalid. - InvalidLineBase, - /// A `.debug_line` reference is invalid. - InvalidLineRef, - /// A `.debug_info` unit entry reference is invalid. - InvalidUnitRef, - /// A `.debug_info` reference is invalid. - InvalidDebugInfoRef, - /// Invalid relative address in a range list. - InvalidRangeRelativeAddress, - /// Writing this CFI instruction is not implemented yet. - UnsupportedCfiInstruction, - /// Writing indirect pointers is not implemented yet. - UnsupportedIndirectAddress, - /// Writing this expression operation is not implemented yet. - UnsupportedOperation, - /// Operation branch target is invalid. - InvalidBranchTarget, - /// Writing this unit type is not supported yet. - UnsupportedUnitType, - } - - impl fmt::Display for ConvertError { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { - use self::ConvertError::*; - match *self { - Read(ref e) => e.fmt(f), - UnsupportedAttributeValue => { - write!(f, "Writing of this attribute value is not implemented yet.") - } - InvalidAttributeValue => write!( - f, - "This attribute value is an invalid name/form combination." - ), - InvalidDebugInfoOffset => write!( - f, - "A `.debug_info` reference does not refer to a valid entry." - ), - InvalidAddress => write!(f, "An address could not be converted."), - UnsupportedLineInstruction => write!( - f, - "Writing this line number instruction is not implemented yet." - ), - UnsupportedLineStringForm => write!( - f, - "Writing this form of line string is not implemented yet." - ), - InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."), - InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."), - InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."), - InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."), - InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."), - InvalidDebugInfoRef => write!(f, "A `.debug_info` reference is invalid."), - InvalidRangeRelativeAddress => { - write!(f, "Invalid relative address in a range list.") - } - UnsupportedCfiInstruction => { - write!(f, "Writing this CFI instruction is not implemented yet.") - } - UnsupportedIndirectAddress => { - write!(f, "Writing indirect pointers is not implemented yet.") - } - UnsupportedOperation => write!( - f, - "Writing this expression operation is not implemented yet." - ), - InvalidBranchTarget => write!(f, "Operation branch target is invalid."), - UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."), - } - } - } - - impl error::Error for ConvertError {} - - impl From<read::Error> for ConvertError { - fn from(e: read::Error) -> Self { - ConvertError::Read(e) - } - } - - /// The result of a conversion. - pub type ConvertResult<T> = result::Result<T, ConvertError>; -} -#[cfg(feature = "read")] -pub use self::convert::*; diff --git a/vendor/gimli/src/write/op.rs b/vendor/gimli/src/write/op.rs deleted file mode 100644 index 287083b..0000000 --- a/vendor/gimli/src/write/op.rs +++ /dev/null @@ -1,1618 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; - -use crate::common::{Encoding, Register}; -use crate::constants::{self, DwOp}; -use crate::leb128::write::{sleb128_size, uleb128_size}; -use crate::write::{ - Address, DebugInfoReference, Error, Reference, Result, UnitEntryId, UnitOffsets, Writer, -}; - -/// The bytecode for a DWARF expression or location description. -#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] -pub struct Expression { - operations: Vec<Operation>, -} - -impl Expression { - /// Create an empty expression. - #[inline] - pub fn new() -> Self { - Self::default() - } - - /// Create an expression from raw bytecode. - /// - /// This does not support operations that require references, such as `DW_OP_addr`. - #[inline] - pub fn raw(bytecode: Vec<u8>) -> Self { - Expression { - operations: vec![Operation::Raw(bytecode)], - } - } - - /// Add an operation to the expression. - /// - /// This should only be used for operations that have no explicit operands. - pub fn op(&mut self, opcode: DwOp) { - self.operations.push(Operation::Simple(opcode)); - } - - /// Add a `DW_OP_addr` operation to the expression. - pub fn op_addr(&mut self, address: Address) { - self.operations.push(Operation::Address(address)); - } - - /// Add a `DW_OP_constu` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_constu(&mut self, value: u64) { - self.operations.push(Operation::UnsignedConstant(value)); - } - - /// Add a `DW_OP_consts` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_consts(&mut self, value: i64) { - self.operations.push(Operation::SignedConstant(value)); - } - - /// Add a `DW_OP_const_type` or `DW_OP_GNU_const_type` operation to the expression. - pub fn op_const_type(&mut self, base: UnitEntryId, value: Box<[u8]>) { - self.operations.push(Operation::ConstantType(base, value)); - } - - /// Add a `DW_OP_fbreg` operation to the expression. - pub fn op_fbreg(&mut self, offset: i64) { - self.operations.push(Operation::FrameOffset(offset)); - } - - /// Add a `DW_OP_bregx` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_breg(&mut self, register: Register, offset: i64) { - self.operations - .push(Operation::RegisterOffset(register, offset)); - } - - /// Add a `DW_OP_regval_type` or `DW_OP_GNU_regval_type` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_regval_type(&mut self, register: Register, base: UnitEntryId) { - self.operations - .push(Operation::RegisterType(register, base)); - } - - /// Add a `DW_OP_pick` operation to the expression. - /// - /// This may be emitted as a `DW_OP_dup` or `DW_OP_over` operation. - pub fn op_pick(&mut self, index: u8) { - self.operations.push(Operation::Pick(index)); - } - - /// Add a `DW_OP_deref` operation to the expression. - pub fn op_deref(&mut self) { - self.operations.push(Operation::Deref { space: false }); - } - - /// Add a `DW_OP_xderef` operation to the expression. - pub fn op_xderef(&mut self) { - self.operations.push(Operation::Deref { space: true }); - } - - /// Add a `DW_OP_deref_size` operation to the expression. - pub fn op_deref_size(&mut self, size: u8) { - self.operations - .push(Operation::DerefSize { size, space: false }); - } - - /// Add a `DW_OP_xderef_size` operation to the expression. - pub fn op_xderef_size(&mut self, size: u8) { - self.operations - .push(Operation::DerefSize { size, space: true }); - } - - /// Add a `DW_OP_deref_type` or `DW_OP_GNU_deref_type` operation to the expression. - pub fn op_deref_type(&mut self, size: u8, base: UnitEntryId) { - self.operations.push(Operation::DerefType { - size, - base, - space: false, - }); - } - - /// Add a `DW_OP_xderef_type` operation to the expression. - pub fn op_xderef_type(&mut self, size: u8, base: UnitEntryId) { - self.operations.push(Operation::DerefType { - size, - base, - space: true, - }); - } - - /// Add a `DW_OP_plus_uconst` operation to the expression. - pub fn op_plus_uconst(&mut self, value: u64) { - self.operations.push(Operation::PlusConstant(value)); - } - - /// Add a `DW_OP_skip` operation to the expression. - /// - /// Returns the index of the operation. The caller must call `set_target` with - /// this index to set the target of the branch. - pub fn op_skip(&mut self) -> usize { - let index = self.next_index(); - self.operations.push(Operation::Skip(!0)); - index - } - - /// Add a `DW_OP_bra` operation to the expression. - /// - /// Returns the index of the operation. The caller must call `set_target` with - /// this index to set the target of the branch. - pub fn op_bra(&mut self) -> usize { - let index = self.next_index(); - self.operations.push(Operation::Branch(!0)); - index - } - - /// Return the index that will be assigned to the next operation. - /// - /// This can be passed to `set_target`. - #[inline] - pub fn next_index(&self) -> usize { - self.operations.len() - } - - /// Set the target of a `DW_OP_skip` or `DW_OP_bra` operation . - pub fn set_target(&mut self, operation: usize, new_target: usize) { - debug_assert!(new_target <= self.next_index()); - debug_assert_ne!(operation, new_target); - match self.operations[operation] { - Operation::Skip(ref mut target) | Operation::Branch(ref mut target) => { - *target = new_target; - } - _ => unimplemented!(), - } - } - - /// Add a `DW_OP_call4` operation to the expression. - pub fn op_call(&mut self, entry: UnitEntryId) { - self.operations.push(Operation::Call(entry)); - } - - /// Add a `DW_OP_call_ref` operation to the expression. - pub fn op_call_ref(&mut self, entry: Reference) { - self.operations.push(Operation::CallRef(entry)); - } - - /// Add a `DW_OP_convert` or `DW_OP_GNU_convert` operation to the expression. - /// - /// `base` is the DIE of the base type, or `None` for the generic type. - pub fn op_convert(&mut self, base: Option<UnitEntryId>) { - self.operations.push(Operation::Convert(base)); - } - - /// Add a `DW_OP_reinterpret` or `DW_OP_GNU_reinterpret` operation to the expression. - /// - /// `base` is the DIE of the base type, or `None` for the generic type. - pub fn op_reinterpret(&mut self, base: Option<UnitEntryId>) { - self.operations.push(Operation::Reinterpret(base)); - } - - /// Add a `DW_OP_entry_value` or `DW_OP_GNU_entry_value` operation to the expression. - pub fn op_entry_value(&mut self, expression: Expression) { - self.operations.push(Operation::EntryValue(expression)); - } - - /// Add a `DW_OP_regx` operation to the expression. - /// - /// This may be emitted as a smaller equivalent operation. - pub fn op_reg(&mut self, register: Register) { - self.operations.push(Operation::Register(register)); - } - - /// Add a `DW_OP_implicit_value` operation to the expression. - pub fn op_implicit_value(&mut self, data: Box<[u8]>) { - self.operations.push(Operation::ImplicitValue(data)); - } - - /// Add a `DW_OP_implicit_pointer` or `DW_OP_GNU_implicit_pointer` operation to the expression. - pub fn op_implicit_pointer(&mut self, entry: Reference, byte_offset: i64) { - self.operations - .push(Operation::ImplicitPointer { entry, byte_offset }); - } - - /// Add a `DW_OP_piece` operation to the expression. - pub fn op_piece(&mut self, size_in_bytes: u64) { - self.operations.push(Operation::Piece { size_in_bytes }); - } - - /// Add a `DW_OP_bit_piece` operation to the expression. - pub fn op_bit_piece(&mut self, size_in_bits: u64, bit_offset: u64) { - self.operations.push(Operation::BitPiece { - size_in_bits, - bit_offset, - }); - } - - /// Add a `DW_OP_GNU_parameter_ref` operation to the expression. - pub fn op_gnu_parameter_ref(&mut self, entry: UnitEntryId) { - self.operations.push(Operation::ParameterRef(entry)); - } - - /// Add a `DW_OP_WASM_location 0x0` operation to the expression. - pub fn op_wasm_local(&mut self, index: u32) { - self.operations.push(Operation::WasmLocal(index)); - } - - /// Add a `DW_OP_WASM_location 0x1` operation to the expression. - pub fn op_wasm_global(&mut self, index: u32) { - self.operations.push(Operation::WasmGlobal(index)); - } - - /// Add a `DW_OP_WASM_location 0x2` operation to the expression. - pub fn op_wasm_stack(&mut self, index: u32) { - self.operations.push(Operation::WasmStack(index)); - } - - pub(crate) fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize { - let mut size = 0; - for operation in &self.operations { - size += operation.size(encoding, unit_offsets); - } - size - } - - pub(crate) fn write<W: Writer>( - &self, - w: &mut W, - mut refs: Option<&mut Vec<DebugInfoReference>>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - ) -> Result<()> { - // TODO: only calculate offsets if needed? - let mut offsets = Vec::with_capacity(self.operations.len()); - let mut offset = w.len(); - for operation in &self.operations { - offsets.push(offset); - offset += operation.size(encoding, unit_offsets); - } - offsets.push(offset); - for (operation, offset) in self.operations.iter().zip(offsets.iter().copied()) { - debug_assert_eq!(w.len(), offset); - operation.write(w, refs.as_deref_mut(), encoding, unit_offsets, &offsets)?; - } - Ok(()) - } -} - -/// A single DWARF operation. -// -// This type is intentionally not public so that we can change the -// representation of expressions as needed. -// -// Variants are listed in the order they appear in Section 2.5. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum Operation { - /// Raw bytecode. - /// - /// Does not support references. - Raw(Vec<u8>), - /// An operation that has no explicit operands. - /// - /// Represents: - /// - `DW_OP_drop`, `DW_OP_swap`, `DW_OP_rot` - /// - `DW_OP_push_object_address`, `DW_OP_form_tls_address`, `DW_OP_call_frame_cfa` - /// - `DW_OP_abs`, `DW_OP_and`, `DW_OP_div`, `DW_OP_minus`, `DW_OP_mod`, `DW_OP_mul`, - /// `DW_OP_neg`, `DW_OP_not`, `DW_OP_or`, `DW_OP_plus`, `DW_OP_shl`, `DW_OP_shr`, - /// `DW_OP_shra`, `DW_OP_xor` - /// - `DW_OP_le`, `DW_OP_ge`, `DW_OP_eq`, `DW_OP_lt`, `DW_OP_gt`, `DW_OP_ne` - /// - `DW_OP_nop` - /// - `DW_OP_stack_value` - Simple(DwOp), - /// Relocate the address if needed, and push it on the stack. - /// - /// Represents `DW_OP_addr`. - Address(Address), - /// Push an unsigned constant value on the stack. - /// - /// Represents `DW_OP_constu`. - UnsignedConstant(u64), - /// Push a signed constant value on the stack. - /// - /// Represents `DW_OP_consts`. - SignedConstant(i64), - /* TODO: requires .debug_addr write support - /// Read the address at the given index in `.debug_addr, relocate the address if needed, - /// and push it on the stack. - /// - /// Represents `DW_OP_addrx`. - AddressIndex(DebugAddrIndex<Offset>), - /// Read the address at the given index in `.debug_addr, and push it on the stack. - /// Do not relocate the address. - /// - /// Represents `DW_OP_constx`. - ConstantIndex(DebugAddrIndex<Offset>), - */ - /// Interpret the value bytes as a constant of a given type, and push it on the stack. - /// - /// Represents `DW_OP_const_type`. - ConstantType(UnitEntryId, Box<[u8]>), - /// Compute the frame base (using `DW_AT_frame_base`), add the - /// given offset, and then push the resulting sum on the stack. - /// - /// Represents `DW_OP_fbreg`. - FrameOffset(i64), - /// Find the contents of the given register, add the offset, and then - /// push the resulting sum on the stack. - /// - /// Represents `DW_OP_bregx`. - RegisterOffset(Register, i64), - /// Interpret the contents of the given register as a value of the given type, - /// and push it on the stack. - /// - /// Represents `DW_OP_regval_type`. - RegisterType(Register, UnitEntryId), - /// Copy the item at a stack index and push it on top of the stack. - /// - /// Represents `DW_OP_pick`, `DW_OP_dup`, and `DW_OP_over`. - Pick(u8), - /// Pop the topmost value of the stack, dereference it, and push the - /// resulting value. - /// - /// Represents `DW_OP_deref` and `DW_OP_xderef`. - Deref { - /// True if the dereference operation takes an address space - /// argument from the stack; false otherwise. - space: bool, - }, - /// Pop the topmost value of the stack, dereference it to obtain a value - /// of the given size, and push the resulting value. - /// - /// Represents `DW_OP_deref_size` and `DW_OP_xderef_size`. - DerefSize { - /// True if the dereference operation takes an address space - /// argument from the stack; false otherwise. - space: bool, - /// The size of the data to dereference. - size: u8, - }, - /// Pop the topmost value of the stack, dereference it to obtain a value - /// of the given type, and push the resulting value. - /// - /// Represents `DW_OP_deref_type` and `DW_OP_xderef_type`. - DerefType { - /// True if the dereference operation takes an address space - /// argument from the stack; false otherwise. - space: bool, - /// The size of the data to dereference. - size: u8, - /// The DIE of the base type, or `None` for the generic type. - base: UnitEntryId, - }, - /// Add an unsigned constant to the topmost value on the stack. - /// - /// Represents `DW_OP_plus_uconst`. - PlusConstant(u64), - /// Unconditional branch to the target location. - /// - /// The value is the index within the expression of the operation to branch to. - /// This will be converted to a relative offset when writing. - /// - /// Represents `DW_OP_skip`. - Skip(usize), - /// Branch to the target location if the top of stack is nonzero. - /// - /// The value is the index within the expression of the operation to branch to. - /// This will be converted to a relative offset when writing. - /// - /// Represents `DW_OP_bra`. - Branch(usize), - /// Evaluate a DWARF expression as a subroutine. - /// - /// The expression comes from the `DW_AT_location` attribute of the indicated DIE. - /// - /// Represents `DW_OP_call4`. - Call(UnitEntryId), - /// Evaluate an external DWARF expression as a subroutine. - /// - /// The expression comes from the `DW_AT_location` attribute of the indicated DIE, - /// which may be in another compilation unit or shared object. - /// - /// Represents `DW_OP_call_ref`. - CallRef(Reference), - /// Pop the top stack entry, convert it to a different type, and push it on the stack. - /// - /// Represents `DW_OP_convert`. - Convert(Option<UnitEntryId>), - /// Pop the top stack entry, reinterpret the bits in its value as a different type, - /// and push it on the stack. - /// - /// Represents `DW_OP_reinterpret`. - Reinterpret(Option<UnitEntryId>), - /// Evaluate an expression at the entry to the current subprogram, and push it on the stack. - /// - /// Represents `DW_OP_entry_value`. - EntryValue(Expression), - // FIXME: EntryRegister - /// Indicate that this piece's location is in the given register. - /// - /// Completes the piece or expression. - /// - /// Represents `DW_OP_regx`. - Register(Register), - /// The object has no location, but has a known constant value. - /// - /// Completes the piece or expression. - /// - /// Represents `DW_OP_implicit_value`. - ImplicitValue(Box<[u8]>), - /// The object is a pointer to a value which has no actual location, such as - /// an implicit value or a stack value. - /// - /// Completes the piece or expression. - /// - /// Represents `DW_OP_implicit_pointer`. - ImplicitPointer { - /// The DIE of the value that this is an implicit pointer into. - entry: Reference, - /// The byte offset into the value that the implicit pointer points to. - byte_offset: i64, - }, - /// Terminate a piece. - /// - /// Represents `DW_OP_piece`. - Piece { - /// The size of this piece in bytes. - size_in_bytes: u64, - }, - /// Terminate a piece with a size in bits. - /// - /// Represents `DW_OP_bit_piece`. - BitPiece { - /// The size of this piece in bits. - size_in_bits: u64, - /// The bit offset of this piece. - bit_offset: u64, - }, - /// This represents a parameter that was optimized out. - /// - /// The entry is the definition of the parameter, and is matched to - /// the `DW_TAG_GNU_call_site_parameter` in the caller that also - /// points to the same definition of the parameter. - /// - /// Represents `DW_OP_GNU_parameter_ref`. - ParameterRef(UnitEntryId), - /// The index of a local in the currently executing function. - /// - /// Represents `DW_OP_WASM_location 0x00`. - WasmLocal(u32), - /// The index of a global. - /// - /// Represents `DW_OP_WASM_location 0x01`. - WasmGlobal(u32), - /// The index of an item on the operand stack. - /// - /// Represents `DW_OP_WASM_location 0x02`. - WasmStack(u32), -} - -impl Operation { - fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize { - let base_size = |base| { - // Errors are handled during writes. - match unit_offsets { - Some(offsets) => uleb128_size(offsets.unit_offset(base)), - None => 0, - } - }; - 1 + match *self { - Operation::Raw(ref bytecode) => return bytecode.len(), - Operation::Simple(_) => 0, - Operation::Address(_) => encoding.address_size as usize, - Operation::UnsignedConstant(value) => { - if value < 32 { - 0 - } else { - uleb128_size(value) - } - } - Operation::SignedConstant(value) => sleb128_size(value), - Operation::ConstantType(base, ref value) => base_size(base) + 1 + value.len(), - Operation::FrameOffset(offset) => sleb128_size(offset), - Operation::RegisterOffset(register, offset) => { - if register.0 < 32 { - sleb128_size(offset) - } else { - uleb128_size(register.0.into()) + sleb128_size(offset) - } - } - Operation::RegisterType(register, base) => { - uleb128_size(register.0.into()) + base_size(base) - } - Operation::Pick(index) => { - if index > 1 { - 1 - } else { - 0 - } - } - Operation::Deref { .. } => 0, - Operation::DerefSize { .. } => 1, - Operation::DerefType { base, .. } => 1 + base_size(base), - Operation::PlusConstant(value) => uleb128_size(value), - Operation::Skip(_) => 2, - Operation::Branch(_) => 2, - Operation::Call(_) => 4, - Operation::CallRef(_) => encoding.format.word_size() as usize, - Operation::Convert(base) => match base { - Some(base) => base_size(base), - None => 1, - }, - Operation::Reinterpret(base) => match base { - Some(base) => base_size(base), - None => 1, - }, - Operation::EntryValue(ref expression) => { - let length = expression.size(encoding, unit_offsets); - uleb128_size(length as u64) + length - } - Operation::Register(register) => { - if register.0 < 32 { - 0 - } else { - uleb128_size(register.0.into()) - } - } - Operation::ImplicitValue(ref data) => uleb128_size(data.len() as u64) + data.len(), - Operation::ImplicitPointer { byte_offset, .. } => { - encoding.format.word_size() as usize + sleb128_size(byte_offset) - } - Operation::Piece { size_in_bytes } => uleb128_size(size_in_bytes), - Operation::BitPiece { - size_in_bits, - bit_offset, - } => uleb128_size(size_in_bits) + uleb128_size(bit_offset), - Operation::ParameterRef(_) => 4, - Operation::WasmLocal(index) - | Operation::WasmGlobal(index) - | Operation::WasmStack(index) => 1 + uleb128_size(index.into()), - } - } - - pub(crate) fn write<W: Writer>( - &self, - w: &mut W, - refs: Option<&mut Vec<DebugInfoReference>>, - encoding: Encoding, - unit_offsets: Option<&UnitOffsets>, - offsets: &[usize], - ) -> Result<()> { - let entry_offset = |entry| match unit_offsets { - Some(offsets) => { - let offset = offsets.unit_offset(entry); - if offset == 0 { - Err(Error::UnsupportedExpressionForwardReference) - } else { - Ok(offset) - } - } - None => Err(Error::UnsupportedCfiExpressionReference), - }; - match *self { - Operation::Raw(ref bytecode) => w.write(bytecode)?, - Operation::Simple(opcode) => w.write_u8(opcode.0)?, - Operation::Address(address) => { - w.write_u8(constants::DW_OP_addr.0)?; - w.write_address(address, encoding.address_size)?; - } - Operation::UnsignedConstant(value) => { - if value < 32 { - w.write_u8(constants::DW_OP_lit0.0 + value as u8)?; - } else { - w.write_u8(constants::DW_OP_constu.0)?; - w.write_uleb128(value)?; - } - } - Operation::SignedConstant(value) => { - w.write_u8(constants::DW_OP_consts.0)?; - w.write_sleb128(value)?; - } - Operation::ConstantType(base, ref value) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_const_type.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_const_type.0)?; - } - w.write_uleb128(entry_offset(base)?)?; - w.write_udata(value.len() as u64, 1)?; - w.write(value)?; - } - Operation::FrameOffset(offset) => { - w.write_u8(constants::DW_OP_fbreg.0)?; - w.write_sleb128(offset)?; - } - Operation::RegisterOffset(register, offset) => { - if register.0 < 32 { - w.write_u8(constants::DW_OP_breg0.0 + register.0 as u8)?; - } else { - w.write_u8(constants::DW_OP_bregx.0)?; - w.write_uleb128(register.0.into())?; - } - w.write_sleb128(offset)?; - } - Operation::RegisterType(register, base) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_regval_type.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_regval_type.0)?; - } - w.write_uleb128(register.0.into())?; - w.write_uleb128(entry_offset(base)?)?; - } - Operation::Pick(index) => match index { - 0 => w.write_u8(constants::DW_OP_dup.0)?, - 1 => w.write_u8(constants::DW_OP_over.0)?, - _ => { - w.write_u8(constants::DW_OP_pick.0)?; - w.write_u8(index)?; - } - }, - Operation::Deref { space } => { - if space { - w.write_u8(constants::DW_OP_xderef.0)?; - } else { - w.write_u8(constants::DW_OP_deref.0)?; - } - } - Operation::DerefSize { space, size } => { - if space { - w.write_u8(constants::DW_OP_xderef_size.0)?; - } else { - w.write_u8(constants::DW_OP_deref_size.0)?; - } - w.write_u8(size)?; - } - Operation::DerefType { space, size, base } => { - if space { - w.write_u8(constants::DW_OP_xderef_type.0)?; - } else { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_deref_type.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_deref_type.0)?; - } - } - w.write_u8(size)?; - w.write_uleb128(entry_offset(base)?)?; - } - Operation::PlusConstant(value) => { - w.write_u8(constants::DW_OP_plus_uconst.0)?; - w.write_uleb128(value)?; - } - Operation::Skip(target) => { - w.write_u8(constants::DW_OP_skip.0)?; - let offset = offsets[target] as i64 - (w.len() as i64 + 2); - w.write_sdata(offset, 2)?; - } - Operation::Branch(target) => { - w.write_u8(constants::DW_OP_bra.0)?; - let offset = offsets[target] as i64 - (w.len() as i64 + 2); - w.write_sdata(offset, 2)?; - } - Operation::Call(entry) => { - w.write_u8(constants::DW_OP_call4.0)?; - // TODO: this probably won't work in practice, because we may - // only know the offsets of base type DIEs at this point. - w.write_udata(entry_offset(entry)?, 4)?; - } - Operation::CallRef(entry) => { - w.write_u8(constants::DW_OP_call_ref.0)?; - let size = encoding.format.word_size(); - match entry { - Reference::Symbol(symbol) => w.write_reference(symbol, size)?, - Reference::Entry(unit, entry) => { - let refs = refs.ok_or(Error::InvalidReference)?; - refs.push(DebugInfoReference { - offset: w.len(), - unit, - entry, - size, - }); - w.write_udata(0, size)?; - } - } - } - Operation::Convert(base) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_convert.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_convert.0)?; - } - match base { - Some(base) => w.write_uleb128(entry_offset(base)?)?, - None => w.write_u8(0)?, - } - } - Operation::Reinterpret(base) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_reinterpret.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_reinterpret.0)?; - } - match base { - Some(base) => w.write_uleb128(entry_offset(base)?)?, - None => w.write_u8(0)?, - } - } - Operation::EntryValue(ref expression) => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_entry_value.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_entry_value.0)?; - } - let length = expression.size(encoding, unit_offsets); - w.write_uleb128(length as u64)?; - expression.write(w, refs, encoding, unit_offsets)?; - } - Operation::Register(register) => { - if register.0 < 32 { - w.write_u8(constants::DW_OP_reg0.0 + register.0 as u8)?; - } else { - w.write_u8(constants::DW_OP_regx.0)?; - w.write_uleb128(register.0.into())?; - } - } - Operation::ImplicitValue(ref data) => { - w.write_u8(constants::DW_OP_implicit_value.0)?; - w.write_uleb128(data.len() as u64)?; - w.write(data)?; - } - Operation::ImplicitPointer { entry, byte_offset } => { - if encoding.version >= 5 { - w.write_u8(constants::DW_OP_implicit_pointer.0)?; - } else { - w.write_u8(constants::DW_OP_GNU_implicit_pointer.0)?; - } - let size = if encoding.version == 2 { - encoding.address_size - } else { - encoding.format.word_size() - }; - match entry { - Reference::Symbol(symbol) => { - w.write_reference(symbol, size)?; - } - Reference::Entry(unit, entry) => { - let refs = refs.ok_or(Error::InvalidReference)?; - refs.push(DebugInfoReference { - offset: w.len(), - unit, - entry, - size, - }); - w.write_udata(0, size)?; - } - } - w.write_sleb128(byte_offset)?; - } - Operation::Piece { size_in_bytes } => { - w.write_u8(constants::DW_OP_piece.0)?; - w.write_uleb128(size_in_bytes)?; - } - Operation::BitPiece { - size_in_bits, - bit_offset, - } => { - w.write_u8(constants::DW_OP_bit_piece.0)?; - w.write_uleb128(size_in_bits)?; - w.write_uleb128(bit_offset)?; - } - Operation::ParameterRef(entry) => { - w.write_u8(constants::DW_OP_GNU_parameter_ref.0)?; - w.write_udata(entry_offset(entry)?, 4)?; - } - Operation::WasmLocal(index) => { - w.write(&[constants::DW_OP_WASM_location.0, 0])?; - w.write_uleb128(index.into())?; - } - Operation::WasmGlobal(index) => { - w.write(&[constants::DW_OP_WASM_location.0, 1])?; - w.write_uleb128(index.into())?; - } - Operation::WasmStack(index) => { - w.write(&[constants::DW_OP_WASM_location.0, 2])?; - w.write_uleb128(index.into())?; - } - } - Ok(()) - } -} - -#[cfg(feature = "read")] -pub(crate) mod convert { - use super::*; - use crate::common::UnitSectionOffset; - use crate::read::{self, Reader}; - use crate::write::{ConvertError, ConvertResult, UnitEntryId, UnitId}; - use std::collections::HashMap; - - impl Expression { - /// Create an expression from the input expression. - pub fn from<R: Reader<Offset = usize>>( - from_expression: read::Expression<R>, - encoding: Encoding, - dwarf: Option<&read::Dwarf<R>>, - unit: Option<&read::Unit<R>>, - entry_ids: Option<&HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>>, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<Expression> { - let convert_unit_offset = |offset: read::UnitOffset| -> ConvertResult<_> { - let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?; - let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; - let id = entry_ids - .get(&offset.to_unit_section_offset(unit)) - .ok_or(ConvertError::InvalidUnitRef)?; - Ok(id.1) - }; - let convert_debug_info_offset = |offset| -> ConvertResult<_> { - // TODO: support relocations - let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?; - let id = entry_ids - .get(&UnitSectionOffset::DebugInfoOffset(offset)) - .ok_or(ConvertError::InvalidDebugInfoRef)?; - Ok(Reference::Entry(id.0, id.1)) - }; - - // Calculate offsets for use in branch/skip operations. - let mut offsets = Vec::new(); - let mut offset = 0; - let mut from_operations = from_expression.clone().operations(encoding); - while from_operations.next()?.is_some() { - offsets.push(offset); - offset = from_operations.offset_from(&from_expression); - } - offsets.push(from_expression.0.len()); - - let mut from_operations = from_expression.clone().operations(encoding); - let mut operations = Vec::new(); - while let Some(from_operation) = from_operations.next()? { - let operation = match from_operation { - read::Operation::Deref { - base_type, - size, - space, - } => { - if base_type.0 != 0 { - let base = convert_unit_offset(base_type)?; - Operation::DerefType { space, size, base } - } else if size != encoding.address_size { - Operation::DerefSize { space, size } - } else { - Operation::Deref { space } - } - } - read::Operation::Drop => Operation::Simple(constants::DW_OP_drop), - read::Operation::Pick { index } => Operation::Pick(index), - read::Operation::Swap => Operation::Simple(constants::DW_OP_swap), - read::Operation::Rot => Operation::Simple(constants::DW_OP_rot), - read::Operation::Abs => Operation::Simple(constants::DW_OP_abs), - read::Operation::And => Operation::Simple(constants::DW_OP_and), - read::Operation::Div => Operation::Simple(constants::DW_OP_div), - read::Operation::Minus => Operation::Simple(constants::DW_OP_minus), - read::Operation::Mod => Operation::Simple(constants::DW_OP_mod), - read::Operation::Mul => Operation::Simple(constants::DW_OP_mul), - read::Operation::Neg => Operation::Simple(constants::DW_OP_neg), - read::Operation::Not => Operation::Simple(constants::DW_OP_not), - read::Operation::Or => Operation::Simple(constants::DW_OP_or), - read::Operation::Plus => Operation::Simple(constants::DW_OP_plus), - read::Operation::PlusConstant { value } => Operation::PlusConstant(value), - read::Operation::Shl => Operation::Simple(constants::DW_OP_shl), - read::Operation::Shr => Operation::Simple(constants::DW_OP_shr), - read::Operation::Shra => Operation::Simple(constants::DW_OP_shra), - read::Operation::Xor => Operation::Simple(constants::DW_OP_xor), - read::Operation::Eq => Operation::Simple(constants::DW_OP_eq), - read::Operation::Ge => Operation::Simple(constants::DW_OP_ge), - read::Operation::Gt => Operation::Simple(constants::DW_OP_gt), - read::Operation::Le => Operation::Simple(constants::DW_OP_le), - read::Operation::Lt => Operation::Simple(constants::DW_OP_lt), - read::Operation::Ne => Operation::Simple(constants::DW_OP_ne), - read::Operation::Bra { target } => { - let offset = from_operations - .offset_from(&from_expression) - .wrapping_add(i64::from(target) as usize); - let index = offsets - .binary_search(&offset) - .map_err(|_| ConvertError::InvalidBranchTarget)?; - Operation::Branch(index) - } - read::Operation::Skip { target } => { - let offset = from_operations - .offset_from(&from_expression) - .wrapping_add(i64::from(target) as usize); - let index = offsets - .binary_search(&offset) - .map_err(|_| ConvertError::InvalidBranchTarget)?; - Operation::Skip(index) - } - read::Operation::UnsignedConstant { value } => { - Operation::UnsignedConstant(value) - } - read::Operation::SignedConstant { value } => Operation::SignedConstant(value), - read::Operation::Register { register } => Operation::Register(register), - read::Operation::RegisterOffset { - register, - offset, - base_type, - } => { - if base_type.0 != 0 { - Operation::RegisterType(register, convert_unit_offset(base_type)?) - } else { - Operation::RegisterOffset(register, offset) - } - } - read::Operation::FrameOffset { offset } => Operation::FrameOffset(offset), - read::Operation::Nop => Operation::Simple(constants::DW_OP_nop), - read::Operation::PushObjectAddress => { - Operation::Simple(constants::DW_OP_push_object_address) - } - read::Operation::Call { offset } => match offset { - read::DieReference::UnitRef(offset) => { - Operation::Call(convert_unit_offset(offset)?) - } - read::DieReference::DebugInfoRef(offset) => { - Operation::CallRef(convert_debug_info_offset(offset)?) - } - }, - read::Operation::TLS => Operation::Simple(constants::DW_OP_form_tls_address), - read::Operation::CallFrameCFA => { - Operation::Simple(constants::DW_OP_call_frame_cfa) - } - read::Operation::Piece { - size_in_bits, - bit_offset: None, - } => Operation::Piece { - size_in_bytes: size_in_bits / 8, - }, - read::Operation::Piece { - size_in_bits, - bit_offset: Some(bit_offset), - } => Operation::BitPiece { - size_in_bits, - bit_offset, - }, - read::Operation::ImplicitValue { data } => { - Operation::ImplicitValue(data.to_slice()?.into_owned().into()) - } - read::Operation::StackValue => Operation::Simple(constants::DW_OP_stack_value), - read::Operation::ImplicitPointer { value, byte_offset } => { - let entry = convert_debug_info_offset(value)?; - Operation::ImplicitPointer { entry, byte_offset } - } - read::Operation::EntryValue { expression } => { - let expression = Expression::from( - read::Expression(expression), - encoding, - dwarf, - unit, - entry_ids, - convert_address, - )?; - Operation::EntryValue(expression) - } - read::Operation::ParameterRef { offset } => { - let entry = convert_unit_offset(offset)?; - Operation::ParameterRef(entry) - } - read::Operation::Address { address } => { - let address = - convert_address(address).ok_or(ConvertError::InvalidAddress)?; - Operation::Address(address) - } - read::Operation::AddressIndex { index } => { - let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?; - let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; - let val = dwarf.address(unit, index)?; - let address = convert_address(val).ok_or(ConvertError::InvalidAddress)?; - Operation::Address(address) - } - read::Operation::ConstantIndex { index } => { - let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?; - let unit = unit.ok_or(ConvertError::UnsupportedOperation)?; - let val = dwarf.address(unit, index)?; - Operation::UnsignedConstant(val) - } - read::Operation::TypedLiteral { base_type, value } => { - let entry = convert_unit_offset(base_type)?; - Operation::ConstantType(entry, value.to_slice()?.into_owned().into()) - } - read::Operation::Convert { base_type } => { - if base_type.0 == 0 { - Operation::Convert(None) - } else { - let entry = convert_unit_offset(base_type)?; - Operation::Convert(Some(entry)) - } - } - read::Operation::Reinterpret { base_type } => { - if base_type.0 == 0 { - Operation::Reinterpret(None) - } else { - let entry = convert_unit_offset(base_type)?; - Operation::Reinterpret(Some(entry)) - } - } - read::Operation::WasmLocal { index } => Operation::WasmLocal(index), - read::Operation::WasmGlobal { index } => Operation::WasmGlobal(index), - read::Operation::WasmStack { index } => Operation::WasmStack(index), - }; - operations.push(operation); - } - Ok(Expression { operations }) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::common::{ - DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, SectionId, - }; - use crate::read; - use crate::write::{ - DebugLineStrOffsets, DebugStrOffsets, EndianVec, LineProgram, Sections, Unit, UnitTable, - }; - use crate::LittleEndian; - use std::collections::HashMap; - use std::sync::Arc; - - #[test] - fn test_operation() { - for &version in &[3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - let mut units = UnitTable::default(); - let unit_id = units.add(Unit::new(encoding, LineProgram::none())); - let unit = units.get_mut(unit_id); - let entry_id = unit.add(unit.root(), constants::DW_TAG_base_type); - let reference = Reference::Entry(unit_id, entry_id); - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let debug_info_offsets = units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - let unit_offsets = debug_info_offsets.unit_offsets(unit_id); - let debug_info_offset = unit_offsets.debug_info_offset(entry_id); - let entry_offset = - read::UnitOffset(unit_offsets.unit_offset(entry_id) as usize); - - let mut reg_expression = Expression::new(); - reg_expression.op_reg(Register(23)); - - let operations: &[(&dyn Fn(&mut Expression), Operation, read::Operation<_>)] = - &[ - ( - &|x| x.op_deref(), - Operation::Deref { space: false }, - read::Operation::Deref { - base_type: read::UnitOffset(0), - size: address_size, - space: false, - }, - ), - ( - &|x| x.op_xderef(), - Operation::Deref { space: true }, - read::Operation::Deref { - base_type: read::UnitOffset(0), - size: address_size, - space: true, - }, - ), - ( - &|x| x.op_deref_size(2), - Operation::DerefSize { - space: false, - size: 2, - }, - read::Operation::Deref { - base_type: read::UnitOffset(0), - size: 2, - space: false, - }, - ), - ( - &|x| x.op_xderef_size(2), - Operation::DerefSize { - space: true, - size: 2, - }, - read::Operation::Deref { - base_type: read::UnitOffset(0), - size: 2, - space: true, - }, - ), - ( - &|x| x.op_deref_type(2, entry_id), - Operation::DerefType { - space: false, - size: 2, - base: entry_id, - }, - read::Operation::Deref { - base_type: entry_offset, - size: 2, - space: false, - }, - ), - ( - &|x| x.op_xderef_type(2, entry_id), - Operation::DerefType { - space: true, - size: 2, - base: entry_id, - }, - read::Operation::Deref { - base_type: entry_offset, - size: 2, - space: true, - }, - ), - ( - &|x| x.op(constants::DW_OP_drop), - Operation::Simple(constants::DW_OP_drop), - read::Operation::Drop, - ), - ( - &|x| x.op_pick(0), - Operation::Pick(0), - read::Operation::Pick { index: 0 }, - ), - ( - &|x| x.op_pick(1), - Operation::Pick(1), - read::Operation::Pick { index: 1 }, - ), - ( - &|x| x.op_pick(2), - Operation::Pick(2), - read::Operation::Pick { index: 2 }, - ), - ( - &|x| x.op(constants::DW_OP_swap), - Operation::Simple(constants::DW_OP_swap), - read::Operation::Swap, - ), - ( - &|x| x.op(constants::DW_OP_rot), - Operation::Simple(constants::DW_OP_rot), - read::Operation::Rot, - ), - ( - &|x| x.op(constants::DW_OP_abs), - Operation::Simple(constants::DW_OP_abs), - read::Operation::Abs, - ), - ( - &|x| x.op(constants::DW_OP_and), - Operation::Simple(constants::DW_OP_and), - read::Operation::And, - ), - ( - &|x| x.op(constants::DW_OP_div), - Operation::Simple(constants::DW_OP_div), - read::Operation::Div, - ), - ( - &|x| x.op(constants::DW_OP_minus), - Operation::Simple(constants::DW_OP_minus), - read::Operation::Minus, - ), - ( - &|x| x.op(constants::DW_OP_mod), - Operation::Simple(constants::DW_OP_mod), - read::Operation::Mod, - ), - ( - &|x| x.op(constants::DW_OP_mul), - Operation::Simple(constants::DW_OP_mul), - read::Operation::Mul, - ), - ( - &|x| x.op(constants::DW_OP_neg), - Operation::Simple(constants::DW_OP_neg), - read::Operation::Neg, - ), - ( - &|x| x.op(constants::DW_OP_not), - Operation::Simple(constants::DW_OP_not), - read::Operation::Not, - ), - ( - &|x| x.op(constants::DW_OP_or), - Operation::Simple(constants::DW_OP_or), - read::Operation::Or, - ), - ( - &|x| x.op(constants::DW_OP_plus), - Operation::Simple(constants::DW_OP_plus), - read::Operation::Plus, - ), - ( - &|x| x.op_plus_uconst(23), - Operation::PlusConstant(23), - read::Operation::PlusConstant { value: 23 }, - ), - ( - &|x| x.op(constants::DW_OP_shl), - Operation::Simple(constants::DW_OP_shl), - read::Operation::Shl, - ), - ( - &|x| x.op(constants::DW_OP_shr), - Operation::Simple(constants::DW_OP_shr), - read::Operation::Shr, - ), - ( - &|x| x.op(constants::DW_OP_shra), - Operation::Simple(constants::DW_OP_shra), - read::Operation::Shra, - ), - ( - &|x| x.op(constants::DW_OP_xor), - Operation::Simple(constants::DW_OP_xor), - read::Operation::Xor, - ), - ( - &|x| x.op(constants::DW_OP_eq), - Operation::Simple(constants::DW_OP_eq), - read::Operation::Eq, - ), - ( - &|x| x.op(constants::DW_OP_ge), - Operation::Simple(constants::DW_OP_ge), - read::Operation::Ge, - ), - ( - &|x| x.op(constants::DW_OP_gt), - Operation::Simple(constants::DW_OP_gt), - read::Operation::Gt, - ), - ( - &|x| x.op(constants::DW_OP_le), - Operation::Simple(constants::DW_OP_le), - read::Operation::Le, - ), - ( - &|x| x.op(constants::DW_OP_lt), - Operation::Simple(constants::DW_OP_lt), - read::Operation::Lt, - ), - ( - &|x| x.op(constants::DW_OP_ne), - Operation::Simple(constants::DW_OP_ne), - read::Operation::Ne, - ), - ( - &|x| x.op_constu(23), - Operation::UnsignedConstant(23), - read::Operation::UnsignedConstant { value: 23 }, - ), - ( - &|x| x.op_consts(-23), - Operation::SignedConstant(-23), - read::Operation::SignedConstant { value: -23 }, - ), - ( - &|x| x.op_reg(Register(23)), - Operation::Register(Register(23)), - read::Operation::Register { - register: Register(23), - }, - ), - ( - &|x| x.op_reg(Register(123)), - Operation::Register(Register(123)), - read::Operation::Register { - register: Register(123), - }, - ), - ( - &|x| x.op_breg(Register(23), 34), - Operation::RegisterOffset(Register(23), 34), - read::Operation::RegisterOffset { - register: Register(23), - offset: 34, - base_type: read::UnitOffset(0), - }, - ), - ( - &|x| x.op_breg(Register(123), 34), - Operation::RegisterOffset(Register(123), 34), - read::Operation::RegisterOffset { - register: Register(123), - offset: 34, - base_type: read::UnitOffset(0), - }, - ), - ( - &|x| x.op_regval_type(Register(23), entry_id), - Operation::RegisterType(Register(23), entry_id), - read::Operation::RegisterOffset { - register: Register(23), - offset: 0, - base_type: entry_offset, - }, - ), - ( - &|x| x.op_fbreg(34), - Operation::FrameOffset(34), - read::Operation::FrameOffset { offset: 34 }, - ), - ( - &|x| x.op(constants::DW_OP_nop), - Operation::Simple(constants::DW_OP_nop), - read::Operation::Nop, - ), - ( - &|x| x.op(constants::DW_OP_push_object_address), - Operation::Simple(constants::DW_OP_push_object_address), - read::Operation::PushObjectAddress, - ), - ( - &|x| x.op_call(entry_id), - Operation::Call(entry_id), - read::Operation::Call { - offset: read::DieReference::UnitRef(entry_offset), - }, - ), - ( - &|x| x.op_call_ref(reference), - Operation::CallRef(reference), - read::Operation::Call { - offset: read::DieReference::DebugInfoRef(debug_info_offset), - }, - ), - ( - &|x| x.op(constants::DW_OP_form_tls_address), - Operation::Simple(constants::DW_OP_form_tls_address), - read::Operation::TLS, - ), - ( - &|x| x.op(constants::DW_OP_call_frame_cfa), - Operation::Simple(constants::DW_OP_call_frame_cfa), - read::Operation::CallFrameCFA, - ), - ( - &|x| x.op_piece(23), - Operation::Piece { size_in_bytes: 23 }, - read::Operation::Piece { - size_in_bits: 23 * 8, - bit_offset: None, - }, - ), - ( - &|x| x.op_bit_piece(23, 34), - Operation::BitPiece { - size_in_bits: 23, - bit_offset: 34, - }, - read::Operation::Piece { - size_in_bits: 23, - bit_offset: Some(34), - }, - ), - ( - &|x| x.op_implicit_value(vec![23].into()), - Operation::ImplicitValue(vec![23].into()), - read::Operation::ImplicitValue { - data: read::EndianSlice::new(&[23], LittleEndian), - }, - ), - ( - &|x| x.op(constants::DW_OP_stack_value), - Operation::Simple(constants::DW_OP_stack_value), - read::Operation::StackValue, - ), - ( - &|x| x.op_implicit_pointer(reference, 23), - Operation::ImplicitPointer { - entry: reference, - byte_offset: 23, - }, - read::Operation::ImplicitPointer { - value: debug_info_offset, - byte_offset: 23, - }, - ), - ( - &|x| x.op_entry_value(reg_expression.clone()), - Operation::EntryValue(reg_expression.clone()), - read::Operation::EntryValue { - expression: read::EndianSlice::new( - &[constants::DW_OP_reg23.0], - LittleEndian, - ), - }, - ), - ( - &|x| x.op_gnu_parameter_ref(entry_id), - Operation::ParameterRef(entry_id), - read::Operation::ParameterRef { - offset: entry_offset, - }, - ), - ( - &|x| x.op_addr(Address::Constant(23)), - Operation::Address(Address::Constant(23)), - read::Operation::Address { address: 23 }, - ), - ( - &|x| x.op_const_type(entry_id, vec![23].into()), - Operation::ConstantType(entry_id, vec![23].into()), - read::Operation::TypedLiteral { - base_type: entry_offset, - value: read::EndianSlice::new(&[23], LittleEndian), - }, - ), - ( - &|x| x.op_convert(None), - Operation::Convert(None), - read::Operation::Convert { - base_type: read::UnitOffset(0), - }, - ), - ( - &|x| x.op_convert(Some(entry_id)), - Operation::Convert(Some(entry_id)), - read::Operation::Convert { - base_type: entry_offset, - }, - ), - ( - &|x| x.op_reinterpret(None), - Operation::Reinterpret(None), - read::Operation::Reinterpret { - base_type: read::UnitOffset(0), - }, - ), - ( - &|x| x.op_reinterpret(Some(entry_id)), - Operation::Reinterpret(Some(entry_id)), - read::Operation::Reinterpret { - base_type: entry_offset, - }, - ), - ( - &|x| x.op_wasm_local(1000), - Operation::WasmLocal(1000), - read::Operation::WasmLocal { index: 1000 }, - ), - ( - &|x| x.op_wasm_global(1000), - Operation::WasmGlobal(1000), - read::Operation::WasmGlobal { index: 1000 }, - ), - ( - &|x| x.op_wasm_stack(1000), - Operation::WasmStack(1000), - read::Operation::WasmStack { index: 1000 }, - ), - ]; - - let mut expression = Expression::new(); - let start_index = expression.next_index(); - for (f, o, _) in operations { - f(&mut expression); - assert_eq!(expression.operations.last(), Some(o)); - } - - let bra_index = expression.op_bra(); - let skip_index = expression.op_skip(); - expression.op(constants::DW_OP_nop); - let end_index = expression.next_index(); - expression.set_target(bra_index, start_index); - expression.set_target(skip_index, end_index); - - let mut w = EndianVec::new(LittleEndian); - let mut refs = Vec::new(); - expression - .write(&mut w, Some(&mut refs), encoding, Some(&unit_offsets)) - .unwrap(); - for r in &refs { - assert_eq!(r.unit, unit_id); - assert_eq!(r.entry, entry_id); - w.write_offset_at( - r.offset, - debug_info_offset.0, - SectionId::DebugInfo, - r.size, - ) - .unwrap(); - } - - let read_expression = - read::Expression(read::EndianSlice::new(w.slice(), LittleEndian)); - let mut read_operations = read_expression.operations(encoding); - for (_, _, operation) in operations { - assert_eq!(read_operations.next(), Ok(Some(*operation))); - } - - // 4 = DW_OP_skip + i16 + DW_OP_nop - assert_eq!( - read_operations.next(), - Ok(Some(read::Operation::Bra { - target: -(w.len() as i16) + 4 - })) - ); - // 1 = DW_OP_nop - assert_eq!( - read_operations.next(), - Ok(Some(read::Operation::Skip { target: 1 })) - ); - assert_eq!(read_operations.next(), Ok(Some(read::Operation::Nop))); - assert_eq!(read_operations.next(), Ok(None)); - - // Fake the unit. - let unit = read::Unit { - header: read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::new(&[], LittleEndian), - ), - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - - let mut entry_ids = HashMap::new(); - entry_ids.insert(debug_info_offset.into(), (unit_id, entry_id)); - let convert_expression = Expression::from( - read_expression, - encoding, - None, /* dwarf */ - Some(&unit), - Some(&entry_ids), - &|address| Some(Address::Constant(address)), - ) - .unwrap(); - let mut convert_operations = convert_expression.operations.iter(); - for (_, operation, _) in operations { - assert_eq!(convert_operations.next(), Some(operation)); - } - assert_eq!( - convert_operations.next(), - Some(&Operation::Branch(start_index)) - ); - assert_eq!(convert_operations.next(), Some(&Operation::Skip(end_index))); - assert_eq!( - convert_operations.next(), - Some(&Operation::Simple(constants::DW_OP_nop)) - ); - } - } - } - } -} diff --git a/vendor/gimli/src/write/range.rs b/vendor/gimli/src/write/range.rs deleted file mode 100644 index c707e1e..0000000 --- a/vendor/gimli/src/write/range.rs +++ /dev/null @@ -1,416 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{Encoding, RangeListsOffset, SectionId}; -use crate::write::{Address, BaseId, Error, Result, Section, Sections, Writer}; - -define_section!( - DebugRanges, - RangeListsOffset, - "A writable `.debug_ranges` section." -); -define_section!( - DebugRngLists, - RangeListsOffset, - "A writable `.debug_rnglists` section." -); - -define_offsets!( - RangeListOffsets: RangeListId => RangeListsOffset, - "The section offsets of a series of range lists within the `.debug_ranges` or `.debug_rnglists` sections." -); - -define_id!( - RangeListId, - "An identifier for a range list in a `RangeListTable`." -); - -/// A table of range lists that will be stored in a `.debug_ranges` or `.debug_rnglists` section. -#[derive(Debug, Default)] -pub struct RangeListTable { - base_id: BaseId, - ranges: IndexSet<RangeList>, -} - -impl RangeListTable { - /// Add a range list to the table. - pub fn add(&mut self, range_list: RangeList) -> RangeListId { - let (index, _) = self.ranges.insert_full(range_list); - RangeListId::new(self.base_id, index) - } - - /// Write the range list table to the appropriate section for the given DWARF version. - pub(crate) fn write<W: Writer>( - &self, - sections: &mut Sections<W>, - encoding: Encoding, - ) -> Result<RangeListOffsets> { - if self.ranges.is_empty() { - return Ok(RangeListOffsets::none()); - } - - match encoding.version { - 2..=4 => self.write_ranges(&mut sections.debug_ranges, encoding.address_size), - 5 => self.write_rnglists(&mut sections.debug_rnglists, encoding), - _ => Err(Error::UnsupportedVersion(encoding.version)), - } - } - - /// Write the range list table to the `.debug_ranges` section. - fn write_ranges<W: Writer>( - &self, - w: &mut DebugRanges<W>, - address_size: u8, - ) -> Result<RangeListOffsets> { - let mut offsets = Vec::new(); - for range_list in self.ranges.iter() { - offsets.push(w.offset()); - for range in &range_list.0 { - // Note that we must ensure none of the ranges have both begin == 0 and end == 0. - // We do this by ensuring that begin != end, which is a bit more restrictive - // than required, but still seems reasonable. - match *range { - Range::BaseAddress { address } => { - let marker = !0 >> (64 - address_size * 8); - w.write_udata(marker, address_size)?; - w.write_address(address, address_size)?; - } - Range::OffsetPair { begin, end } => { - if begin == end { - return Err(Error::InvalidRange); - } - w.write_udata(begin, address_size)?; - w.write_udata(end, address_size)?; - } - Range::StartEnd { begin, end } => { - if begin == end { - return Err(Error::InvalidRange); - } - w.write_address(begin, address_size)?; - w.write_address(end, address_size)?; - } - Range::StartLength { begin, length } => { - let end = match begin { - Address::Constant(begin) => Address::Constant(begin + length), - Address::Symbol { symbol, addend } => Address::Symbol { - symbol, - addend: addend + length as i64, - }, - }; - if begin == end { - return Err(Error::InvalidRange); - } - w.write_address(begin, address_size)?; - w.write_address(end, address_size)?; - } - } - } - w.write_udata(0, address_size)?; - w.write_udata(0, address_size)?; - } - Ok(RangeListOffsets { - base_id: self.base_id, - offsets, - }) - } - - /// Write the range list table to the `.debug_rnglists` section. - fn write_rnglists<W: Writer>( - &self, - w: &mut DebugRngLists<W>, - encoding: Encoding, - ) -> Result<RangeListOffsets> { - let mut offsets = Vec::new(); - - if encoding.version != 5 { - return Err(Error::NeedVersion(5)); - } - - let length_offset = w.write_initial_length(encoding.format)?; - let length_base = w.len(); - - w.write_u16(encoding.version)?; - w.write_u8(encoding.address_size)?; - w.write_u8(0)?; // segment_selector_size - w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) - // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list - - for range_list in self.ranges.iter() { - offsets.push(w.offset()); - for range in &range_list.0 { - match *range { - Range::BaseAddress { address } => { - w.write_u8(crate::constants::DW_RLE_base_address.0)?; - w.write_address(address, encoding.address_size)?; - } - Range::OffsetPair { begin, end } => { - w.write_u8(crate::constants::DW_RLE_offset_pair.0)?; - w.write_uleb128(begin)?; - w.write_uleb128(end)?; - } - Range::StartEnd { begin, end } => { - w.write_u8(crate::constants::DW_RLE_start_end.0)?; - w.write_address(begin, encoding.address_size)?; - w.write_address(end, encoding.address_size)?; - } - Range::StartLength { begin, length } => { - w.write_u8(crate::constants::DW_RLE_start_length.0)?; - w.write_address(begin, encoding.address_size)?; - w.write_uleb128(length)?; - } - } - } - - w.write_u8(crate::constants::DW_RLE_end_of_list.0)?; - } - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, encoding.format)?; - - Ok(RangeListOffsets { - base_id: self.base_id, - offsets, - }) - } -} - -/// A range list that will be stored in a `.debug_ranges` or `.debug_rnglists` section. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct RangeList(pub Vec<Range>); - -/// A single range. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum Range { - /// DW_RLE_base_address - BaseAddress { - /// Base address. - address: Address, - }, - /// DW_RLE_offset_pair - OffsetPair { - /// Start of range relative to base address. - begin: u64, - /// End of range relative to base address. - end: u64, - }, - /// DW_RLE_start_end - StartEnd { - /// Start of range. - begin: Address, - /// End of range. - end: Address, - }, - /// DW_RLE_start_length - StartLength { - /// Start of range. - begin: Address, - /// Length of range. - length: u64, - }, -} - -#[cfg(feature = "read")] -mod convert { - use super::*; - - use crate::read::{self, Reader}; - use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; - - impl RangeList { - /// Create a range list by reading the data from the give range list iter. - pub(crate) fn from<R: Reader<Offset = usize>>( - mut from: read::RawRngListIter<R>, - context: &ConvertUnitContext<R>, - ) -> ConvertResult<Self> { - let mut have_base_address = context.base_address != Address::Constant(0); - let convert_address = - |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); - let mut ranges = Vec::new(); - while let Some(from_range) = from.next()? { - let range = match from_range { - read::RawRngListEntry::AddressOrOffsetPair { begin, end } => { - // These were parsed as addresses, even if they are offsets. - let begin = convert_address(begin)?; - let end = convert_address(end)?; - match (begin, end) { - (Address::Constant(begin_offset), Address::Constant(end_offset)) => { - if have_base_address { - Range::OffsetPair { - begin: begin_offset, - end: end_offset, - } - } else { - Range::StartEnd { begin, end } - } - } - _ => { - if have_base_address { - // At least one of begin/end is an address, but we also have - // a base address. Adding addresses is undefined. - return Err(ConvertError::InvalidRangeRelativeAddress); - } - Range::StartEnd { begin, end } - } - } - } - read::RawRngListEntry::BaseAddress { addr } => { - have_base_address = true; - let address = convert_address(addr)?; - Range::BaseAddress { address } - } - read::RawRngListEntry::BaseAddressx { addr } => { - have_base_address = true; - let address = convert_address(context.dwarf.address(context.unit, addr)?)?; - Range::BaseAddress { address } - } - read::RawRngListEntry::StartxEndx { begin, end } => { - let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; - let end = convert_address(context.dwarf.address(context.unit, end)?)?; - Range::StartEnd { begin, end } - } - read::RawRngListEntry::StartxLength { begin, length } => { - let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; - Range::StartLength { begin, length } - } - read::RawRngListEntry::OffsetPair { begin, end } => { - Range::OffsetPair { begin, end } - } - read::RawRngListEntry::StartEnd { begin, end } => { - let begin = convert_address(begin)?; - let end = convert_address(end)?; - Range::StartEnd { begin, end } - } - read::RawRngListEntry::StartLength { begin, length } => { - let begin = convert_address(begin)?; - Range::StartLength { begin, length } - } - }; - // Filtering empty ranges out. - match range { - Range::StartLength { length, .. } if length == 0 => continue, - Range::StartEnd { begin, end, .. } if begin == end => continue, - Range::OffsetPair { begin, end, .. } if begin == end => continue, - _ => (), - } - ranges.push(range); - } - Ok(RangeList(ranges)) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::common::{ - DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, - DebugStrOffsetsBase, Format, - }; - use crate::read; - use crate::write::{ - ConvertUnitContext, EndianVec, LineStringTable, LocationListTable, Range, RangeListTable, - StringTable, - }; - use crate::LittleEndian; - use std::collections::HashMap; - use std::sync::Arc; - - #[test] - fn test_range() { - let mut line_strings = LineStringTable::default(); - let mut strings = StringTable::default(); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - let mut range_list = RangeList(vec![ - Range::StartLength { - begin: Address::Constant(6666), - length: 7777, - }, - Range::StartEnd { - begin: Address::Constant(4444), - end: Address::Constant(5555), - }, - Range::BaseAddress { - address: Address::Constant(1111), - }, - Range::OffsetPair { - begin: 2222, - end: 3333, - }, - ]); - - let mut ranges = RangeListTable::default(); - let range_list_id = ranges.add(range_list.clone()); - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let range_list_offsets = ranges.write(&mut sections, encoding).unwrap(); - - let read_debug_ranges = - read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian); - let read_debug_rnglists = - read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian); - let read_ranges = read::RangeLists::new(read_debug_ranges, read_debug_rnglists); - let offset = range_list_offsets.get(range_list_id); - let read_range_list = read_ranges.raw_ranges(offset, encoding).unwrap(); - - let dwarf = read::Dwarf { - ranges: read_ranges, - ..Default::default() - }; - let unit = read::Unit { - header: read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::default(), - ), - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - let context = ConvertUnitContext { - dwarf: &dwarf, - unit: &unit, - line_strings: &mut line_strings, - strings: &mut strings, - ranges: &mut ranges, - locations: &mut LocationListTable::default(), - convert_address: &|address| Some(Address::Constant(address)), - base_address: Address::Constant(0), - line_program_offset: None, - line_program_files: Vec::new(), - entry_ids: &HashMap::new(), - }; - let convert_range_list = RangeList::from(read_range_list, &context).unwrap(); - - if version <= 4 { - range_list.0[0] = Range::StartEnd { - begin: Address::Constant(6666), - end: Address::Constant(6666 + 7777), - }; - } - assert_eq!(range_list, convert_range_list); - } - } - } - } -} diff --git a/vendor/gimli/src/write/section.rs b/vendor/gimli/src/write/section.rs deleted file mode 100644 index db5eb9a..0000000 --- a/vendor/gimli/src/write/section.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::ops::DerefMut; -use std::result; -use std::vec::Vec; - -use crate::common::SectionId; -use crate::write::{ - DebugAbbrev, DebugFrame, DebugInfo, DebugInfoReference, DebugLine, DebugLineStr, DebugLoc, - DebugLocLists, DebugRanges, DebugRngLists, DebugStr, EhFrame, Writer, -}; - -macro_rules! define_section { - ($name:ident, $offset:ident, $docs:expr) => { - #[doc=$docs] - #[derive(Debug, Default)] - pub struct $name<W: Writer>(pub W); - - impl<W: Writer> $name<W> { - /// Return the offset of the next write. - pub fn offset(&self) -> $offset { - $offset(self.len()) - } - } - - impl<W: Writer> From<W> for $name<W> { - #[inline] - fn from(w: W) -> Self { - $name(w) - } - } - - impl<W: Writer> Deref for $name<W> { - type Target = W; - - #[inline] - fn deref(&self) -> &W { - &self.0 - } - } - - impl<W: Writer> DerefMut for $name<W> { - #[inline] - fn deref_mut(&mut self) -> &mut W { - &mut self.0 - } - } - - impl<W: Writer> Section<W> for $name<W> { - #[inline] - fn id(&self) -> SectionId { - SectionId::$name - } - } - }; -} - -/// Functionality common to all writable DWARF sections. -pub trait Section<W: Writer>: DerefMut<Target = W> { - /// Returns the DWARF section kind for this type. - fn id(&self) -> SectionId; - - /// Returns the ELF section name for this type. - fn name(&self) -> &'static str { - self.id().name() - } -} - -/// All of the writable DWARF sections. -#[derive(Debug, Default)] -pub struct Sections<W: Writer> { - /// The `.debug_abbrev` section. - pub debug_abbrev: DebugAbbrev<W>, - /// The `.debug_info` section. - pub debug_info: DebugInfo<W>, - /// The `.debug_line` section. - pub debug_line: DebugLine<W>, - /// The `.debug_line_str` section. - pub debug_line_str: DebugLineStr<W>, - /// The `.debug_ranges` section. - pub debug_ranges: DebugRanges<W>, - /// The `.debug_rnglists` section. - pub debug_rnglists: DebugRngLists<W>, - /// The `.debug_loc` section. - pub debug_loc: DebugLoc<W>, - /// The `.debug_loclists` section. - pub debug_loclists: DebugLocLists<W>, - /// The `.debug_str` section. - pub debug_str: DebugStr<W>, - /// The `.debug_frame` section. - pub debug_frame: DebugFrame<W>, - /// The `.eh_frame` section. - pub eh_frame: EhFrame<W>, - /// Unresolved references in the `.debug_info` section. - pub(crate) debug_info_refs: Vec<DebugInfoReference>, - /// Unresolved references in the `.debug_loc` section. - pub(crate) debug_loc_refs: Vec<DebugInfoReference>, - /// Unresolved references in the `.debug_loclists` section. - pub(crate) debug_loclists_refs: Vec<DebugInfoReference>, -} - -impl<W: Writer + Clone> Sections<W> { - /// Create a new `Sections` using clones of the given `section`. - pub fn new(section: W) -> Self { - Sections { - debug_abbrev: DebugAbbrev(section.clone()), - debug_info: DebugInfo(section.clone()), - debug_line: DebugLine(section.clone()), - debug_line_str: DebugLineStr(section.clone()), - debug_ranges: DebugRanges(section.clone()), - debug_rnglists: DebugRngLists(section.clone()), - debug_loc: DebugLoc(section.clone()), - debug_loclists: DebugLocLists(section.clone()), - debug_str: DebugStr(section.clone()), - debug_frame: DebugFrame(section.clone()), - eh_frame: EhFrame(section), - debug_info_refs: Vec::new(), - debug_loc_refs: Vec::new(), - debug_loclists_refs: Vec::new(), - } - } -} - -impl<W: Writer> Sections<W> { - /// For each section, call `f` once with a shared reference. - pub fn for_each<F, E>(&self, mut f: F) -> result::Result<(), E> - where - F: FnMut(SectionId, &W) -> result::Result<(), E>, - { - macro_rules! f { - ($s:expr) => { - f($s.id(), &$s) - }; - } - // Ordered so that earlier sections do not reference later sections. - f!(self.debug_abbrev)?; - f!(self.debug_str)?; - f!(self.debug_line_str)?; - f!(self.debug_line)?; - f!(self.debug_ranges)?; - f!(self.debug_rnglists)?; - f!(self.debug_loc)?; - f!(self.debug_loclists)?; - f!(self.debug_info)?; - f!(self.debug_frame)?; - f!(self.eh_frame)?; - Ok(()) - } - - /// For each section, call `f` once with a mutable reference. - pub fn for_each_mut<F, E>(&mut self, mut f: F) -> result::Result<(), E> - where - F: FnMut(SectionId, &mut W) -> result::Result<(), E>, - { - macro_rules! f { - ($s:expr) => { - f($s.id(), &mut $s) - }; - } - // Ordered so that earlier sections do not reference later sections. - f!(self.debug_abbrev)?; - f!(self.debug_str)?; - f!(self.debug_line_str)?; - f!(self.debug_line)?; - f!(self.debug_ranges)?; - f!(self.debug_rnglists)?; - f!(self.debug_loc)?; - f!(self.debug_loclists)?; - f!(self.debug_info)?; - f!(self.debug_frame)?; - f!(self.eh_frame)?; - Ok(()) - } -} diff --git a/vendor/gimli/src/write/str.rs b/vendor/gimli/src/write/str.rs deleted file mode 100644 index 83285c0..0000000 --- a/vendor/gimli/src/write/str.rs +++ /dev/null @@ -1,172 +0,0 @@ -use alloc::vec::Vec; -use indexmap::IndexSet; -use std::ops::{Deref, DerefMut}; - -use crate::common::{DebugLineStrOffset, DebugStrOffset, SectionId}; -use crate::write::{BaseId, Result, Section, Writer}; - -// Requirements: -// - values are `[u8]`, null bytes are not allowed -// - insertion returns a fixed id -// - inserting a duplicate returns the id of the existing value -// - able to convert an id to a section offset -// Optional? -// - able to get an existing value given an id -// -// Limitations of current implementation (using IndexSet): -// - inserting requires either an allocation for duplicates, -// or a double lookup for non-duplicates -// - doesn't preserve offsets when updating an existing `.debug_str` section -// -// Possible changes: -// - calculate offsets as we add values, and use that as the id. -// This would avoid the need for DebugStrOffsets but would make it -// hard to implement `get`. -macro_rules! define_string_table { - ($name:ident, $id:ident, $section:ident, $offsets:ident, $docs:expr) => { - #[doc=$docs] - #[derive(Debug, Default)] - pub struct $name { - base_id: BaseId, - strings: IndexSet<Vec<u8>>, - } - - impl $name { - /// Add a string to the string table and return its id. - /// - /// If the string already exists, then return the id of the existing string. - /// - /// # Panics - /// - /// Panics if `bytes` contains a null byte. - pub fn add<T>(&mut self, bytes: T) -> $id - where - T: Into<Vec<u8>>, - { - let bytes = bytes.into(); - assert!(!bytes.contains(&0)); - let (index, _) = self.strings.insert_full(bytes); - $id::new(self.base_id, index) - } - - /// Return the number of strings in the table. - #[inline] - pub fn count(&self) -> usize { - self.strings.len() - } - - /// Get a reference to a string in the table. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - pub fn get(&self, id: $id) -> &[u8] { - debug_assert_eq!(self.base_id, id.base_id); - self.strings.get_index(id.index).map(Vec::as_slice).unwrap() - } - - /// Write the string table to the `.debug_str` section. - /// - /// Returns the offsets at which the strings are written. - pub fn write<W: Writer>(&self, w: &mut $section<W>) -> Result<$offsets> { - let mut offsets = Vec::new(); - for bytes in self.strings.iter() { - offsets.push(w.offset()); - w.write(bytes)?; - w.write_u8(0)?; - } - - Ok($offsets { - base_id: self.base_id, - offsets, - }) - } - } - }; -} - -define_id!(StringId, "An identifier for a string in a `StringTable`."); - -define_string_table!( - StringTable, - StringId, - DebugStr, - DebugStrOffsets, - "A table of strings that will be stored in a `.debug_str` section." -); - -define_section!(DebugStr, DebugStrOffset, "A writable `.debug_str` section."); - -define_offsets!( - DebugStrOffsets: StringId => DebugStrOffset, - "The section offsets of all strings within a `.debug_str` section." -); - -define_id!( - LineStringId, - "An identifier for a string in a `LineStringTable`." -); - -define_string_table!( - LineStringTable, - LineStringId, - DebugLineStr, - DebugLineStrOffsets, - "A table of strings that will be stored in a `.debug_line_str` section." -); - -define_section!( - DebugLineStr, - DebugLineStrOffset, - "A writable `.debug_line_str` section." -); - -define_offsets!( - DebugLineStrOffsets: LineStringId => DebugLineStrOffset, - "The section offsets of all strings within a `.debug_line_str` section." -); - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::read; - use crate::write::EndianVec; - use crate::LittleEndian; - - #[test] - fn test_string_table() { - let mut strings = StringTable::default(); - assert_eq!(strings.count(), 0); - let id1 = strings.add(&b"one"[..]); - let id2 = strings.add(&b"two"[..]); - assert_eq!(strings.add(&b"one"[..]), id1); - assert_eq!(strings.add(&b"two"[..]), id2); - assert_eq!(strings.get(id1), &b"one"[..]); - assert_eq!(strings.get(id2), &b"two"[..]); - assert_eq!(strings.count(), 2); - - let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); - let offsets = strings.write(&mut debug_str).unwrap(); - assert_eq!(debug_str.slice(), b"one\0two\0"); - assert_eq!(offsets.get(id1), DebugStrOffset(0)); - assert_eq!(offsets.get(id2), DebugStrOffset(4)); - assert_eq!(offsets.count(), 2); - } - - #[test] - fn test_string_table_read() { - let mut strings = StringTable::default(); - let id1 = strings.add(&b"one"[..]); - let id2 = strings.add(&b"two"[..]); - - let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); - let offsets = strings.write(&mut debug_str).unwrap(); - - let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian); - let str1 = read_debug_str.get_str(offsets.get(id1)).unwrap(); - let str2 = read_debug_str.get_str(offsets.get(id2)).unwrap(); - assert_eq!(str1.slice(), &b"one"[..]); - assert_eq!(str2.slice(), &b"two"[..]); - } -} diff --git a/vendor/gimli/src/write/unit.rs b/vendor/gimli/src/write/unit.rs deleted file mode 100644 index dd8ba67..0000000 --- a/vendor/gimli/src/write/unit.rs +++ /dev/null @@ -1,3152 +0,0 @@ -use alloc::vec::Vec; -use std::ops::{Deref, DerefMut}; -use std::{slice, usize}; - -use crate::common::{ - DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugMacroOffset, - DebugStrOffset, DebugTypeSignature, Encoding, Format, SectionId, -}; -use crate::constants; -use crate::leb128::write::{sleb128_size, uleb128_size}; -use crate::write::{ - Abbreviation, AbbreviationTable, Address, AttributeSpecification, BaseId, DebugLineStrOffsets, - DebugStrOffsets, Error, Expression, FileId, LineProgram, LineStringId, LocationListId, - LocationListOffsets, LocationListTable, RangeListId, RangeListOffsets, RangeListTable, - Reference, Result, Section, Sections, StringId, Writer, -}; - -define_id!(UnitId, "An identifier for a unit in a `UnitTable`."); - -define_id!(UnitEntryId, "An identifier for an entry in a `Unit`."); - -/// A table of units that will be stored in the `.debug_info` section. -#[derive(Debug, Default)] -pub struct UnitTable { - base_id: BaseId, - units: Vec<Unit>, -} - -impl UnitTable { - /// Create a new unit and add it to the table. - /// - /// `address_size` must be in bytes. - /// - /// Returns the `UnitId` of the new unit. - #[inline] - pub fn add(&mut self, unit: Unit) -> UnitId { - let id = UnitId::new(self.base_id, self.units.len()); - self.units.push(unit); - id - } - - /// Return the number of units. - #[inline] - pub fn count(&self) -> usize { - self.units.len() - } - - /// Return the id of a unit. - /// - /// # Panics - /// - /// Panics if `index >= self.count()`. - #[inline] - pub fn id(&self, index: usize) -> UnitId { - assert!(index < self.count()); - UnitId::new(self.base_id, index) - } - - /// Get a reference to a unit. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get(&self, id: UnitId) -> &Unit { - debug_assert_eq!(self.base_id, id.base_id); - &self.units[id.index] - } - - /// Get a mutable reference to a unit. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get_mut(&mut self, id: UnitId) -> &mut Unit { - debug_assert_eq!(self.base_id, id.base_id); - &mut self.units[id.index] - } - - /// Write the units to the given sections. - /// - /// `strings` must contain the `.debug_str` offsets of the corresponding - /// `StringTable`. - pub fn write<W: Writer>( - &mut self, - sections: &mut Sections<W>, - line_strings: &DebugLineStrOffsets, - strings: &DebugStrOffsets, - ) -> Result<DebugInfoOffsets> { - let mut offsets = DebugInfoOffsets { - base_id: self.base_id, - units: Vec::new(), - }; - for unit in &mut self.units { - // TODO: maybe share abbreviation tables - let abbrev_offset = sections.debug_abbrev.offset(); - let mut abbrevs = AbbreviationTable::default(); - - offsets.units.push(unit.write( - sections, - abbrev_offset, - &mut abbrevs, - line_strings, - strings, - )?); - - abbrevs.write(&mut sections.debug_abbrev)?; - } - - write_section_refs( - &mut sections.debug_info_refs, - &mut sections.debug_info.0, - &offsets, - )?; - write_section_refs( - &mut sections.debug_loc_refs, - &mut sections.debug_loc.0, - &offsets, - )?; - write_section_refs( - &mut sections.debug_loclists_refs, - &mut sections.debug_loclists.0, - &offsets, - )?; - - Ok(offsets) - } -} - -fn write_section_refs<W: Writer>( - references: &mut Vec<DebugInfoReference>, - w: &mut W, - offsets: &DebugInfoOffsets, -) -> Result<()> { - for r in references.drain(..) { - let entry_offset = offsets.entry(r.unit, r.entry).0; - debug_assert_ne!(entry_offset, 0); - w.write_offset_at(r.offset, entry_offset, SectionId::DebugInfo, r.size)?; - } - Ok(()) -} - -/// A unit's debugging information. -#[derive(Debug)] -pub struct Unit { - base_id: BaseId, - /// The encoding parameters for this unit. - encoding: Encoding, - /// The line number program for this unit. - pub line_program: LineProgram, - /// A table of range lists used by this unit. - pub ranges: RangeListTable, - /// A table of location lists used by this unit. - pub locations: LocationListTable, - /// All entries in this unit. The order is unrelated to the tree order. - // Requirements: - // - entries form a tree - // - entries can be added in any order - // - entries have a fixed id - // - able to quickly lookup an entry from its id - // Limitations of current implementation: - // - mutable iteration of children is messy due to borrow checker - entries: Vec<DebuggingInformationEntry>, - /// The index of the root entry in entries. - root: UnitEntryId, -} - -impl Unit { - /// Create a new `Unit`. - pub fn new(encoding: Encoding, line_program: LineProgram) -> Self { - let base_id = BaseId::default(); - let ranges = RangeListTable::default(); - let locations = LocationListTable::default(); - let mut entries = Vec::new(); - let root = DebuggingInformationEntry::new( - base_id, - &mut entries, - None, - constants::DW_TAG_compile_unit, - ); - Unit { - base_id, - encoding, - line_program, - ranges, - locations, - entries, - root, - } - } - - /// Return the encoding parameters for this unit. - #[inline] - pub fn encoding(&self) -> Encoding { - self.encoding - } - - /// Return the DWARF version for this unit. - #[inline] - pub fn version(&self) -> u16 { - self.encoding.version - } - - /// Return the address size in bytes for this unit. - #[inline] - pub fn address_size(&self) -> u8 { - self.encoding.address_size - } - - /// Return the DWARF format for this unit. - #[inline] - pub fn format(&self) -> Format { - self.encoding.format - } - - /// Return the number of `DebuggingInformationEntry`s created for this unit. - /// - /// This includes entries that no longer have a parent. - #[inline] - pub fn count(&self) -> usize { - self.entries.len() - } - - /// Return the id of the root entry. - #[inline] - pub fn root(&self) -> UnitEntryId { - self.root - } - - /// Add a new `DebuggingInformationEntry` to this unit and return its id. - /// - /// The `parent` must be within the same unit. - /// - /// # Panics - /// - /// Panics if `parent` is invalid. - #[inline] - pub fn add(&mut self, parent: UnitEntryId, tag: constants::DwTag) -> UnitEntryId { - debug_assert_eq!(self.base_id, parent.base_id); - DebuggingInformationEntry::new(self.base_id, &mut self.entries, Some(parent), tag) - } - - /// Get a reference to an entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get(&self, id: UnitEntryId) -> &DebuggingInformationEntry { - debug_assert_eq!(self.base_id, id.base_id); - &self.entries[id.index] - } - - /// Get a mutable reference to an entry. - /// - /// # Panics - /// - /// Panics if `id` is invalid. - #[inline] - pub fn get_mut(&mut self, id: UnitEntryId) -> &mut DebuggingInformationEntry { - debug_assert_eq!(self.base_id, id.base_id); - &mut self.entries[id.index] - } - - /// Return true if `self.line_program` is used by a DIE. - fn line_program_in_use(&self) -> bool { - if self.line_program.is_none() { - return false; - } - if !self.line_program.is_empty() { - return true; - } - - for entry in &self.entries { - for attr in &entry.attrs { - if let AttributeValue::FileIndex(Some(_)) = attr.value { - return true; - } - } - } - - false - } - - /// Write the unit to the given sections. - pub(crate) fn write<W: Writer>( - &mut self, - sections: &mut Sections<W>, - abbrev_offset: DebugAbbrevOffset, - abbrevs: &mut AbbreviationTable, - line_strings: &DebugLineStrOffsets, - strings: &DebugStrOffsets, - ) -> Result<UnitOffsets> { - let line_program = if self.line_program_in_use() { - self.entries[self.root.index] - .set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); - Some(self.line_program.write( - &mut sections.debug_line, - self.encoding, - line_strings, - strings, - )?) - } else { - self.entries[self.root.index].delete(constants::DW_AT_stmt_list); - None - }; - - // TODO: use .debug_types for type units in DWARF v4. - let w = &mut sections.debug_info; - - let mut offsets = UnitOffsets { - base_id: self.base_id, - unit: w.offset(), - // Entries can be written in any order, so create the complete vec now. - entries: vec![EntryOffset::none(); self.entries.len()], - }; - - let length_offset = w.write_initial_length(self.format())?; - let length_base = w.len(); - - w.write_u16(self.version())?; - if 2 <= self.version() && self.version() <= 4 { - w.write_offset( - abbrev_offset.0, - SectionId::DebugAbbrev, - self.format().word_size(), - )?; - w.write_u8(self.address_size())?; - } else if self.version() == 5 { - w.write_u8(constants::DW_UT_compile.0)?; - w.write_u8(self.address_size())?; - w.write_offset( - abbrev_offset.0, - SectionId::DebugAbbrev, - self.format().word_size(), - )?; - } else { - return Err(Error::UnsupportedVersion(self.version())); - } - - // Calculate all DIE offsets, so that we are able to output references to them. - // However, references to base types in expressions use ULEB128, so base types - // must be moved to the front before we can calculate offsets. - self.reorder_base_types(); - let mut offset = w.len(); - self.entries[self.root.index].calculate_offsets( - self, - &mut offset, - &mut offsets, - abbrevs, - )?; - - let range_lists = self.ranges.write(sections, self.encoding)?; - // Location lists can't be written until we have DIE offsets. - let loc_lists = self - .locations - .write(sections, self.encoding, Some(&offsets))?; - - let w = &mut sections.debug_info; - let mut unit_refs = Vec::new(); - self.entries[self.root.index].write( - w, - &mut sections.debug_info_refs, - &mut unit_refs, - self, - &mut offsets, - line_program, - line_strings, - strings, - &range_lists, - &loc_lists, - )?; - - let length = (w.len() - length_base) as u64; - w.write_initial_length_at(length_offset, length, self.format())?; - - for (offset, entry) in unit_refs { - // This does not need relocation. - w.write_udata_at( - offset.0, - offsets.unit_offset(entry), - self.format().word_size(), - )?; - } - - Ok(offsets) - } - - /// Reorder base types to come first so that typed stack operations - /// can get their offset. - fn reorder_base_types(&mut self) { - let root = &self.entries[self.root.index]; - let mut root_children = Vec::with_capacity(root.children.len()); - for entry in &root.children { - if self.entries[entry.index].tag == constants::DW_TAG_base_type { - root_children.push(*entry); - } - } - for entry in &root.children { - if self.entries[entry.index].tag != constants::DW_TAG_base_type { - root_children.push(*entry); - } - } - self.entries[self.root.index].children = root_children; - } -} - -/// A Debugging Information Entry (DIE). -/// -/// DIEs have a set of attributes and optionally have children DIEs as well. -/// -/// DIEs form a tree without any cycles. This is enforced by specifying the -/// parent when creating a DIE, and disallowing changes of parent. -#[derive(Debug)] -pub struct DebuggingInformationEntry { - id: UnitEntryId, - parent: Option<UnitEntryId>, - tag: constants::DwTag, - /// Whether to emit `DW_AT_sibling`. - sibling: bool, - attrs: Vec<Attribute>, - children: Vec<UnitEntryId>, -} - -impl DebuggingInformationEntry { - /// Create a new `DebuggingInformationEntry`. - /// - /// # Panics - /// - /// Panics if `parent` is invalid. - #[allow(clippy::new_ret_no_self)] - fn new( - base_id: BaseId, - entries: &mut Vec<DebuggingInformationEntry>, - parent: Option<UnitEntryId>, - tag: constants::DwTag, - ) -> UnitEntryId { - let id = UnitEntryId::new(base_id, entries.len()); - entries.push(DebuggingInformationEntry { - id, - parent, - tag, - sibling: false, - attrs: Vec::new(), - children: Vec::new(), - }); - if let Some(parent) = parent { - debug_assert_eq!(base_id, parent.base_id); - assert_ne!(parent, id); - entries[parent.index].children.push(id); - } - id - } - - /// Return the id of this entry. - #[inline] - pub fn id(&self) -> UnitEntryId { - self.id - } - - /// Return the parent of this entry. - #[inline] - pub fn parent(&self) -> Option<UnitEntryId> { - self.parent - } - - /// Return the tag of this entry. - #[inline] - pub fn tag(&self) -> constants::DwTag { - self.tag - } - - /// Return `true` if a `DW_AT_sibling` attribute will be emitted. - #[inline] - pub fn sibling(&self) -> bool { - self.sibling - } - - /// Set whether a `DW_AT_sibling` attribute will be emitted. - /// - /// The attribute will only be emitted if the DIE has children. - #[inline] - pub fn set_sibling(&mut self, sibling: bool) { - self.sibling = sibling; - } - - /// Iterate over the attributes of this entry. - #[inline] - pub fn attrs(&self) -> slice::Iter<Attribute> { - self.attrs.iter() - } - - /// Iterate over the attributes of this entry for modification. - #[inline] - pub fn attrs_mut(&mut self) -> slice::IterMut<Attribute> { - self.attrs.iter_mut() - } - - /// Get an attribute. - pub fn get(&self, name: constants::DwAt) -> Option<&AttributeValue> { - self.attrs - .iter() - .find(|attr| attr.name == name) - .map(|attr| &attr.value) - } - - /// Get an attribute for modification. - pub fn get_mut(&mut self, name: constants::DwAt) -> Option<&mut AttributeValue> { - self.attrs - .iter_mut() - .find(|attr| attr.name == name) - .map(|attr| &mut attr.value) - } - - /// Set an attribute. - /// - /// Replaces any existing attribute with the same name. - /// - /// # Panics - /// - /// Panics if `name` is `DW_AT_sibling`. Use `set_sibling` instead. - pub fn set(&mut self, name: constants::DwAt, value: AttributeValue) { - assert_ne!(name, constants::DW_AT_sibling); - if let Some(attr) = self.attrs.iter_mut().find(|attr| attr.name == name) { - attr.value = value; - return; - } - self.attrs.push(Attribute { name, value }); - } - - /// Delete an attribute. - /// - /// Replaces any existing attribute with the same name. - pub fn delete(&mut self, name: constants::DwAt) { - self.attrs.retain(|x| x.name != name); - } - - /// Iterate over the children of this entry. - /// - /// Note: use `Unit::add` to add a new child to this entry. - #[inline] - pub fn children(&self) -> slice::Iter<UnitEntryId> { - self.children.iter() - } - - /// Delete a child entry and all of its children. - pub fn delete_child(&mut self, id: UnitEntryId) { - self.children.retain(|&child| child != id); - } - - /// Return the type abbreviation for this DIE. - fn abbreviation(&self, encoding: Encoding) -> Result<Abbreviation> { - let mut attrs = Vec::new(); - - if self.sibling && !self.children.is_empty() { - let form = match encoding.format { - Format::Dwarf32 => constants::DW_FORM_ref4, - Format::Dwarf64 => constants::DW_FORM_ref8, - }; - attrs.push(AttributeSpecification::new(constants::DW_AT_sibling, form)); - } - - for attr in &self.attrs { - attrs.push(attr.specification(encoding)?); - } - - Ok(Abbreviation::new( - self.tag, - !self.children.is_empty(), - attrs, - )) - } - - fn calculate_offsets( - &self, - unit: &Unit, - offset: &mut usize, - offsets: &mut UnitOffsets, - abbrevs: &mut AbbreviationTable, - ) -> Result<()> { - offsets.entries[self.id.index].offset = DebugInfoOffset(*offset); - offsets.entries[self.id.index].abbrev = abbrevs.add(self.abbreviation(unit.encoding())?); - *offset += self.size(unit, offsets); - if !self.children.is_empty() { - for child in &self.children { - unit.entries[child.index].calculate_offsets(unit, offset, offsets, abbrevs)?; - } - // Null child - *offset += 1; - } - Ok(()) - } - - fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize { - let mut size = uleb128_size(offsets.abbrev(self.id)); - if self.sibling && !self.children.is_empty() { - size += unit.format().word_size() as usize; - } - for attr in &self.attrs { - size += attr.value.size(unit, offsets); - } - size - } - - /// Write the entry to the given sections. - fn write<W: Writer>( - &self, - w: &mut DebugInfo<W>, - debug_info_refs: &mut Vec<DebugInfoReference>, - unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, - unit: &Unit, - offsets: &mut UnitOffsets, - line_program: Option<DebugLineOffset>, - line_strings: &DebugLineStrOffsets, - strings: &DebugStrOffsets, - range_lists: &RangeListOffsets, - loc_lists: &LocationListOffsets, - ) -> Result<()> { - debug_assert_eq!(offsets.debug_info_offset(self.id), w.offset()); - w.write_uleb128(offsets.abbrev(self.id))?; - - let sibling_offset = if self.sibling && !self.children.is_empty() { - let offset = w.offset(); - w.write_udata(0, unit.format().word_size())?; - Some(offset) - } else { - None - }; - - for attr in &self.attrs { - attr.value.write( - w, - debug_info_refs, - unit_refs, - unit, - offsets, - line_program, - line_strings, - strings, - range_lists, - loc_lists, - )?; - } - - if !self.children.is_empty() { - for child in &self.children { - unit.entries[child.index].write( - w, - debug_info_refs, - unit_refs, - unit, - offsets, - line_program, - line_strings, - strings, - range_lists, - loc_lists, - )?; - } - // Null child - w.write_u8(0)?; - } - - if let Some(offset) = sibling_offset { - let next_offset = (w.offset().0 - offsets.unit.0) as u64; - // This does not need relocation. - w.write_udata_at(offset.0, next_offset, unit.format().word_size())?; - } - Ok(()) - } -} - -/// An attribute in a `DebuggingInformationEntry`, consisting of a name and -/// associated value. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Attribute { - name: constants::DwAt, - value: AttributeValue, -} - -impl Attribute { - /// Get the name of this attribute. - #[inline] - pub fn name(&self) -> constants::DwAt { - self.name - } - - /// Get the value of this attribute. - #[inline] - pub fn get(&self) -> &AttributeValue { - &self.value - } - - /// Set the value of this attribute. - #[inline] - pub fn set(&mut self, value: AttributeValue) { - self.value = value; - } - - /// Return the type specification for this attribute. - fn specification(&self, encoding: Encoding) -> Result<AttributeSpecification> { - Ok(AttributeSpecification::new( - self.name, - self.value.form(encoding)?, - )) - } -} - -/// The value of an attribute in a `DebuggingInformationEntry`. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum AttributeValue { - /// "Refers to some location in the address space of the described program." - Address(Address), - - /// A slice of an arbitrary number of bytes. - Block(Vec<u8>), - - /// A one byte constant data value. How to interpret the byte depends on context. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data1(u8), - - /// A two byte constant data value. How to interpret the bytes depends on context. - /// - /// This value will be converted to the target endian before writing. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data2(u16), - - /// A four byte constant data value. How to interpret the bytes depends on context. - /// - /// This value will be converted to the target endian before writing. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data4(u32), - - /// An eight byte constant data value. How to interpret the bytes depends on context. - /// - /// This value will be converted to the target endian before writing. - /// - /// From section 7 of the standard: "Depending on context, it may be a - /// signed integer, an unsigned integer, a floating-point constant, or - /// anything else." - Data8(u64), - - /// A signed integer constant. - Sdata(i64), - - /// An unsigned integer constant. - Udata(u64), - - /// "The information bytes contain a DWARF expression (see Section 2.5) or - /// location description (see Section 2.6)." - Exprloc(Expression), - - /// A boolean that indicates presence or absence of the attribute. - Flag(bool), - - /// An attribute that is always present. - FlagPresent, - - /// A reference to a `DebuggingInformationEntry` in this unit. - UnitRef(UnitEntryId), - - /// A reference to a `DebuggingInformationEntry` in a potentially different unit. - DebugInfoRef(Reference), - - /// An offset into the `.debug_info` section of the supplementary object file. - /// - /// The API does not currently assist with generating this offset. - /// This variant will be removed from the API once support for writing - /// supplementary object files is implemented. - DebugInfoRefSup(DebugInfoOffset), - - /// A reference to a line number program. - LineProgramRef, - - /// A reference to a location list. - LocationListRef(LocationListId), - - /// An offset into the `.debug_macinfo` section. - /// - /// The API does not currently assist with generating this offset. - /// This variant will be removed from the API once support for writing - /// `.debug_macinfo` sections is implemented. - DebugMacinfoRef(DebugMacinfoOffset), - - /// An offset into the `.debug_macro` section. - /// - /// The API does not currently assist with generating this offset. - /// This variant will be removed from the API once support for writing - /// `.debug_macro` sections is implemented. - DebugMacroRef(DebugMacroOffset), - - /// A reference to a range list. - RangeListRef(RangeListId), - - /// A type signature. - /// - /// The API does not currently assist with generating this signature. - /// This variant will be removed from the API once support for writing - /// `.debug_types` sections is implemented. - DebugTypesRef(DebugTypeSignature), - - /// A reference to a string in the `.debug_str` section. - StringRef(StringId), - - /// An offset into the `.debug_str` section of the supplementary object file. - /// - /// The API does not currently assist with generating this offset. - /// This variant will be removed from the API once support for writing - /// supplementary object files is implemented. - DebugStrRefSup(DebugStrOffset), - - /// A reference to a string in the `.debug_line_str` section. - LineStringRef(LineStringId), - - /// A slice of bytes representing a string. Must not include null bytes. - /// Not guaranteed to be UTF-8 or anything like that. - String(Vec<u8>), - - /// The value of a `DW_AT_encoding` attribute. - Encoding(constants::DwAte), - - /// The value of a `DW_AT_decimal_sign` attribute. - DecimalSign(constants::DwDs), - - /// The value of a `DW_AT_endianity` attribute. - Endianity(constants::DwEnd), - - /// The value of a `DW_AT_accessibility` attribute. - Accessibility(constants::DwAccess), - - /// The value of a `DW_AT_visibility` attribute. - Visibility(constants::DwVis), - - /// The value of a `DW_AT_virtuality` attribute. - Virtuality(constants::DwVirtuality), - - /// The value of a `DW_AT_language` attribute. - Language(constants::DwLang), - - /// The value of a `DW_AT_address_class` attribute. - AddressClass(constants::DwAddr), - - /// The value of a `DW_AT_identifier_case` attribute. - IdentifierCase(constants::DwId), - - /// The value of a `DW_AT_calling_convention` attribute. - CallingConvention(constants::DwCc), - - /// The value of a `DW_AT_inline` attribute. - Inline(constants::DwInl), - - /// The value of a `DW_AT_ordering` attribute. - Ordering(constants::DwOrd), - - /// An index into the filename entries from the line number information - /// table for the unit containing this value. - FileIndex(Option<FileId>), -} - -impl AttributeValue { - /// Return the form that will be used to encode this value. - pub fn form(&self, encoding: Encoding) -> Result<constants::DwForm> { - // TODO: missing forms: - // - DW_FORM_indirect - // - DW_FORM_implicit_const - // - FW_FORM_block1/block2/block4 - // - DW_FORM_str/strx1/strx2/strx3/strx4 - // - DW_FORM_addrx/addrx1/addrx2/addrx3/addrx4 - // - DW_FORM_data16 - // - DW_FORM_line_strp - // - DW_FORM_loclistx - // - DW_FORM_rnglistx - let form = match *self { - AttributeValue::Address(_) => constants::DW_FORM_addr, - AttributeValue::Block(_) => constants::DW_FORM_block, - AttributeValue::Data1(_) => constants::DW_FORM_data1, - AttributeValue::Data2(_) => constants::DW_FORM_data2, - AttributeValue::Data4(_) => constants::DW_FORM_data4, - AttributeValue::Data8(_) => constants::DW_FORM_data8, - AttributeValue::Exprloc(_) => constants::DW_FORM_exprloc, - AttributeValue::Flag(_) => constants::DW_FORM_flag, - AttributeValue::FlagPresent => constants::DW_FORM_flag_present, - AttributeValue::UnitRef(_) => { - // Using a fixed size format lets us write a placeholder before we know - // the value. - match encoding.format { - Format::Dwarf32 => constants::DW_FORM_ref4, - Format::Dwarf64 => constants::DW_FORM_ref8, - } - } - AttributeValue::DebugInfoRef(_) => constants::DW_FORM_ref_addr, - AttributeValue::DebugInfoRefSup(_) => { - // TODO: should this depend on the size of supplementary section? - match encoding.format { - Format::Dwarf32 => constants::DW_FORM_ref_sup4, - Format::Dwarf64 => constants::DW_FORM_ref_sup8, - } - } - AttributeValue::LineProgramRef - | AttributeValue::LocationListRef(_) - | AttributeValue::DebugMacinfoRef(_) - | AttributeValue::DebugMacroRef(_) - | AttributeValue::RangeListRef(_) => { - if encoding.version == 2 || encoding.version == 3 { - match encoding.format { - Format::Dwarf32 => constants::DW_FORM_data4, - Format::Dwarf64 => constants::DW_FORM_data8, - } - } else { - constants::DW_FORM_sec_offset - } - } - AttributeValue::DebugTypesRef(_) => constants::DW_FORM_ref_sig8, - AttributeValue::StringRef(_) => constants::DW_FORM_strp, - AttributeValue::DebugStrRefSup(_) => constants::DW_FORM_strp_sup, - AttributeValue::LineStringRef(_) => constants::DW_FORM_line_strp, - AttributeValue::String(_) => constants::DW_FORM_string, - AttributeValue::Encoding(_) - | AttributeValue::DecimalSign(_) - | AttributeValue::Endianity(_) - | AttributeValue::Accessibility(_) - | AttributeValue::Visibility(_) - | AttributeValue::Virtuality(_) - | AttributeValue::Language(_) - | AttributeValue::AddressClass(_) - | AttributeValue::IdentifierCase(_) - | AttributeValue::CallingConvention(_) - | AttributeValue::Inline(_) - | AttributeValue::Ordering(_) - | AttributeValue::FileIndex(_) - | AttributeValue::Udata(_) => constants::DW_FORM_udata, - AttributeValue::Sdata(_) => constants::DW_FORM_sdata, - }; - Ok(form) - } - - fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize { - macro_rules! debug_assert_form { - ($form:expr) => { - debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form) - }; - } - match *self { - AttributeValue::Address(_) => { - debug_assert_form!(constants::DW_FORM_addr); - unit.address_size() as usize - } - AttributeValue::Block(ref val) => { - debug_assert_form!(constants::DW_FORM_block); - uleb128_size(val.len() as u64) + val.len() - } - AttributeValue::Data1(_) => { - debug_assert_form!(constants::DW_FORM_data1); - 1 - } - AttributeValue::Data2(_) => { - debug_assert_form!(constants::DW_FORM_data2); - 2 - } - AttributeValue::Data4(_) => { - debug_assert_form!(constants::DW_FORM_data4); - 4 - } - AttributeValue::Data8(_) => { - debug_assert_form!(constants::DW_FORM_data8); - 8 - } - AttributeValue::Sdata(val) => { - debug_assert_form!(constants::DW_FORM_sdata); - sleb128_size(val) - } - AttributeValue::Udata(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val) - } - AttributeValue::Exprloc(ref val) => { - debug_assert_form!(constants::DW_FORM_exprloc); - let size = val.size(unit.encoding(), Some(offsets)); - uleb128_size(size as u64) + size - } - AttributeValue::Flag(_) => { - debug_assert_form!(constants::DW_FORM_flag); - 1 - } - AttributeValue::FlagPresent => { - debug_assert_form!(constants::DW_FORM_flag_present); - 0 - } - AttributeValue::UnitRef(_) => { - match unit.format() { - Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4), - Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8), - } - unit.format().word_size() as usize - } - AttributeValue::DebugInfoRef(_) => { - debug_assert_form!(constants::DW_FORM_ref_addr); - if unit.version() == 2 { - unit.address_size() as usize - } else { - unit.format().word_size() as usize - } - } - AttributeValue::DebugInfoRefSup(_) => { - match unit.format() { - Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4), - Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8), - } - unit.format().word_size() as usize - } - AttributeValue::LineProgramRef => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::LocationListRef(_) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::DebugMacinfoRef(_) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::DebugMacroRef(_) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::RangeListRef(_) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - unit.format().word_size() as usize - } - AttributeValue::DebugTypesRef(_) => { - debug_assert_form!(constants::DW_FORM_ref_sig8); - 8 - } - AttributeValue::StringRef(_) => { - debug_assert_form!(constants::DW_FORM_strp); - unit.format().word_size() as usize - } - AttributeValue::DebugStrRefSup(_) => { - debug_assert_form!(constants::DW_FORM_strp_sup); - unit.format().word_size() as usize - } - AttributeValue::LineStringRef(_) => { - debug_assert_form!(constants::DW_FORM_line_strp); - unit.format().word_size() as usize - } - AttributeValue::String(ref val) => { - debug_assert_form!(constants::DW_FORM_string); - val.len() + 1 - } - AttributeValue::Encoding(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::DecimalSign(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Endianity(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Accessibility(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Visibility(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Virtuality(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Language(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::AddressClass(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::IdentifierCase(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::CallingConvention(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Inline(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::Ordering(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.0 as u64) - } - AttributeValue::FileIndex(val) => { - debug_assert_form!(constants::DW_FORM_udata); - uleb128_size(val.map(FileId::raw).unwrap_or(0)) - } - } - } - - /// Write the attribute value to the given sections. - fn write<W: Writer>( - &self, - w: &mut DebugInfo<W>, - debug_info_refs: &mut Vec<DebugInfoReference>, - unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, - unit: &Unit, - offsets: &UnitOffsets, - line_program: Option<DebugLineOffset>, - line_strings: &DebugLineStrOffsets, - strings: &DebugStrOffsets, - range_lists: &RangeListOffsets, - loc_lists: &LocationListOffsets, - ) -> Result<()> { - macro_rules! debug_assert_form { - ($form:expr) => { - debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form) - }; - } - match *self { - AttributeValue::Address(val) => { - debug_assert_form!(constants::DW_FORM_addr); - w.write_address(val, unit.address_size())?; - } - AttributeValue::Block(ref val) => { - debug_assert_form!(constants::DW_FORM_block); - w.write_uleb128(val.len() as u64)?; - w.write(val)?; - } - AttributeValue::Data1(val) => { - debug_assert_form!(constants::DW_FORM_data1); - w.write_u8(val)?; - } - AttributeValue::Data2(val) => { - debug_assert_form!(constants::DW_FORM_data2); - w.write_u16(val)?; - } - AttributeValue::Data4(val) => { - debug_assert_form!(constants::DW_FORM_data4); - w.write_u32(val)?; - } - AttributeValue::Data8(val) => { - debug_assert_form!(constants::DW_FORM_data8); - w.write_u64(val)?; - } - AttributeValue::Sdata(val) => { - debug_assert_form!(constants::DW_FORM_sdata); - w.write_sleb128(val)?; - } - AttributeValue::Udata(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(val)?; - } - AttributeValue::Exprloc(ref val) => { - debug_assert_form!(constants::DW_FORM_exprloc); - w.write_uleb128(val.size(unit.encoding(), Some(offsets)) as u64)?; - val.write( - &mut w.0, - Some(debug_info_refs), - unit.encoding(), - Some(offsets), - )?; - } - AttributeValue::Flag(val) => { - debug_assert_form!(constants::DW_FORM_flag); - w.write_u8(val as u8)?; - } - AttributeValue::FlagPresent => { - debug_assert_form!(constants::DW_FORM_flag_present); - } - AttributeValue::UnitRef(id) => { - match unit.format() { - Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4), - Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8), - } - unit_refs.push((w.offset(), id)); - w.write_udata(0, unit.format().word_size())?; - } - AttributeValue::DebugInfoRef(reference) => { - debug_assert_form!(constants::DW_FORM_ref_addr); - let size = if unit.version() == 2 { - unit.address_size() - } else { - unit.format().word_size() - }; - match reference { - Reference::Symbol(symbol) => w.write_reference(symbol, size)?, - Reference::Entry(unit, entry) => { - debug_info_refs.push(DebugInfoReference { - offset: w.len(), - unit, - entry, - size, - }); - w.write_udata(0, size)?; - } - } - } - AttributeValue::DebugInfoRefSup(val) => { - match unit.format() { - Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4), - Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8), - } - w.write_udata(val.0 as u64, unit.format().word_size())?; - } - AttributeValue::LineProgramRef => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - match line_program { - Some(line_program) => { - w.write_offset( - line_program.0, - SectionId::DebugLine, - unit.format().word_size(), - )?; - } - None => return Err(Error::InvalidAttributeValue), - } - } - AttributeValue::LocationListRef(val) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - let section = if unit.version() <= 4 { - SectionId::DebugLoc - } else { - SectionId::DebugLocLists - }; - w.write_offset(loc_lists.get(val).0, section, unit.format().word_size())?; - } - AttributeValue::DebugMacinfoRef(val) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - w.write_offset(val.0, SectionId::DebugMacinfo, unit.format().word_size())?; - } - AttributeValue::DebugMacroRef(val) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - w.write_offset(val.0, SectionId::DebugMacro, unit.format().word_size())?; - } - AttributeValue::RangeListRef(val) => { - if unit.version() >= 4 { - debug_assert_form!(constants::DW_FORM_sec_offset); - } - let section = if unit.version() <= 4 { - SectionId::DebugRanges - } else { - SectionId::DebugRngLists - }; - w.write_offset(range_lists.get(val).0, section, unit.format().word_size())?; - } - AttributeValue::DebugTypesRef(val) => { - debug_assert_form!(constants::DW_FORM_ref_sig8); - w.write_u64(val.0)?; - } - AttributeValue::StringRef(val) => { - debug_assert_form!(constants::DW_FORM_strp); - w.write_offset( - strings.get(val).0, - SectionId::DebugStr, - unit.format().word_size(), - )?; - } - AttributeValue::DebugStrRefSup(val) => { - debug_assert_form!(constants::DW_FORM_strp_sup); - w.write_udata(val.0 as u64, unit.format().word_size())?; - } - AttributeValue::LineStringRef(val) => { - debug_assert_form!(constants::DW_FORM_line_strp); - w.write_offset( - line_strings.get(val).0, - SectionId::DebugLineStr, - unit.format().word_size(), - )?; - } - AttributeValue::String(ref val) => { - debug_assert_form!(constants::DW_FORM_string); - w.write(val)?; - w.write_u8(0)?; - } - AttributeValue::Encoding(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::DecimalSign(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Endianity(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Accessibility(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Visibility(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Virtuality(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Language(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::AddressClass(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(val.0)?; - } - AttributeValue::IdentifierCase(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::CallingConvention(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Inline(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::Ordering(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(u64::from(val.0))?; - } - AttributeValue::FileIndex(val) => { - debug_assert_form!(constants::DW_FORM_udata); - w.write_uleb128(val.map(FileId::raw).unwrap_or(0))?; - } - } - Ok(()) - } -} - -define_section!( - DebugInfo, - DebugInfoOffset, - "A writable `.debug_info` section." -); - -/// The section offsets of all elements within a `.debug_info` section. -#[derive(Debug, Default)] -pub struct DebugInfoOffsets { - base_id: BaseId, - units: Vec<UnitOffsets>, -} - -impl DebugInfoOffsets { - #[cfg(test)] - #[cfg(feature = "read")] - pub(crate) fn unit_offsets(&self, unit: UnitId) -> &UnitOffsets { - debug_assert_eq!(self.base_id, unit.base_id); - &self.units[unit.index] - } - - /// Get the `.debug_info` section offset for the given unit. - #[inline] - pub fn unit(&self, unit: UnitId) -> DebugInfoOffset { - debug_assert_eq!(self.base_id, unit.base_id); - self.units[unit.index].unit - } - - /// Get the `.debug_info` section offset for the given entry. - #[inline] - pub fn entry(&self, unit: UnitId, entry: UnitEntryId) -> DebugInfoOffset { - debug_assert_eq!(self.base_id, unit.base_id); - self.units[unit.index].debug_info_offset(entry) - } -} - -/// The section offsets of all elements of a unit within a `.debug_info` section. -#[derive(Debug)] -pub(crate) struct UnitOffsets { - base_id: BaseId, - unit: DebugInfoOffset, - entries: Vec<EntryOffset>, -} - -impl UnitOffsets { - #[cfg(test)] - #[cfg(feature = "read")] - fn none() -> Self { - UnitOffsets { - base_id: BaseId::default(), - unit: DebugInfoOffset(0), - entries: Vec::new(), - } - } - - /// Get the .debug_info offset for the given entry. - #[inline] - pub(crate) fn debug_info_offset(&self, entry: UnitEntryId) -> DebugInfoOffset { - debug_assert_eq!(self.base_id, entry.base_id); - let offset = self.entries[entry.index].offset; - debug_assert_ne!(offset.0, 0); - offset - } - - /// Get the unit offset for the given entry. - #[inline] - pub(crate) fn unit_offset(&self, entry: UnitEntryId) -> u64 { - let offset = self.debug_info_offset(entry); - (offset.0 - self.unit.0) as u64 - } - - /// Get the abbreviation code for the given entry. - #[inline] - pub(crate) fn abbrev(&self, entry: UnitEntryId) -> u64 { - debug_assert_eq!(self.base_id, entry.base_id); - self.entries[entry.index].abbrev - } -} - -#[derive(Debug, Clone, Copy)] -pub(crate) struct EntryOffset { - offset: DebugInfoOffset, - abbrev: u64, -} - -impl EntryOffset { - fn none() -> Self { - EntryOffset { - offset: DebugInfoOffset(0), - abbrev: 0, - } - } -} - -/// A reference to a `.debug_info` entry that has yet to be resolved. -#[derive(Debug, Clone, Copy)] -pub(crate) struct DebugInfoReference { - /// The offset within the section of the reference. - pub offset: usize, - /// The size of the reference. - pub size: u8, - /// The unit containing the entry. - pub unit: UnitId, - /// The entry being referenced. - pub entry: UnitEntryId, -} - -#[cfg(feature = "read")] -pub(crate) mod convert { - use super::*; - use crate::common::{DwoId, UnitSectionOffset}; - use crate::read::{self, Reader}; - use crate::write::{self, ConvertError, ConvertResult, LocationList, RangeList}; - use std::collections::HashMap; - - pub(crate) struct ConvertUnit<R: Reader<Offset = usize>> { - from_unit: read::Unit<R>, - base_id: BaseId, - encoding: Encoding, - entries: Vec<DebuggingInformationEntry>, - entry_offsets: Vec<read::UnitOffset>, - root: UnitEntryId, - } - - pub(crate) struct ConvertUnitContext<'a, R: Reader<Offset = usize>> { - pub dwarf: &'a read::Dwarf<R>, - pub unit: &'a read::Unit<R>, - pub line_strings: &'a mut write::LineStringTable, - pub strings: &'a mut write::StringTable, - pub ranges: &'a mut write::RangeListTable, - pub locations: &'a mut write::LocationListTable, - pub convert_address: &'a dyn Fn(u64) -> Option<Address>, - pub base_address: Address, - pub line_program_offset: Option<DebugLineOffset>, - pub line_program_files: Vec<FileId>, - pub entry_ids: &'a HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, - } - - impl UnitTable { - /// Create a unit table by reading the data in the given sections. - /// - /// This also updates the given tables with the values that are referenced from - /// attributes in this section. - /// - /// `convert_address` is a function to convert read addresses into the `Address` - /// type. For non-relocatable addresses, this function may simply return - /// `Address::Constant(address)`. For relocatable addresses, it is the caller's - /// responsibility to determine the symbol and addend corresponding to the address - /// and return `Address::Symbol { symbol, addend }`. - pub fn from<R: Reader<Offset = usize>>( - dwarf: &read::Dwarf<R>, - line_strings: &mut write::LineStringTable, - strings: &mut write::StringTable, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<UnitTable> { - let base_id = BaseId::default(); - let mut unit_entries = Vec::new(); - let mut entry_ids = HashMap::new(); - - let mut from_units = dwarf.units(); - while let Some(from_unit) = from_units.next()? { - let unit_id = UnitId::new(base_id, unit_entries.len()); - unit_entries.push(Unit::convert_entries( - from_unit, - unit_id, - &mut entry_ids, - dwarf, - )?); - } - - // Attributes must be converted in a separate pass so that we can handle - // references to other compilation units. - let mut units = Vec::new(); - for unit_entries in unit_entries.drain(..) { - units.push(Unit::convert_attributes( - unit_entries, - &entry_ids, - dwarf, - line_strings, - strings, - convert_address, - )?); - } - - Ok(UnitTable { base_id, units }) - } - } - - impl Unit { - /// Create a unit by reading the data in the input sections. - /// - /// Does not add entry attributes. - pub(crate) fn convert_entries<R: Reader<Offset = usize>>( - from_header: read::UnitHeader<R>, - unit_id: UnitId, - entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, - dwarf: &read::Dwarf<R>, - ) -> ConvertResult<ConvertUnit<R>> { - match from_header.type_() { - read::UnitType::Compilation => (), - _ => return Err(ConvertError::UnsupportedUnitType), - } - let base_id = BaseId::default(); - - let from_unit = dwarf.unit(from_header)?; - let encoding = from_unit.encoding(); - - let mut entries = Vec::new(); - let mut entry_offsets = Vec::new(); - - let mut from_tree = from_unit.entries_tree(None)?; - let from_root = from_tree.root()?; - let root = DebuggingInformationEntry::convert_entry( - from_root, - &from_unit, - base_id, - &mut entries, - &mut entry_offsets, - entry_ids, - None, - unit_id, - )?; - - Ok(ConvertUnit { - from_unit, - base_id, - encoding, - entries, - entry_offsets, - root, - }) - } - - /// Create entry attributes by reading the data in the input sections. - fn convert_attributes<R: Reader<Offset = usize>>( - unit: ConvertUnit<R>, - entry_ids: &HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, - dwarf: &read::Dwarf<R>, - line_strings: &mut write::LineStringTable, - strings: &mut write::StringTable, - convert_address: &dyn Fn(u64) -> Option<Address>, - ) -> ConvertResult<Unit> { - let from_unit = unit.from_unit; - let base_address = - convert_address(from_unit.low_pc).ok_or(ConvertError::InvalidAddress)?; - - let (line_program_offset, line_program, line_program_files) = - match from_unit.line_program { - Some(ref from_program) => { - let from_program = from_program.clone(); - let line_program_offset = from_program.header().offset(); - let (line_program, line_program_files) = LineProgram::from( - from_program, - dwarf, - line_strings, - strings, - convert_address, - )?; - (Some(line_program_offset), line_program, line_program_files) - } - None => (None, LineProgram::none(), Vec::new()), - }; - - let mut ranges = RangeListTable::default(); - let mut locations = LocationListTable::default(); - - let mut context = ConvertUnitContext { - entry_ids, - dwarf, - unit: &from_unit, - line_strings, - strings, - ranges: &mut ranges, - locations: &mut locations, - convert_address, - base_address, - line_program_offset, - line_program_files, - }; - - let mut entries = unit.entries; - for entry in &mut entries { - entry.convert_attributes(&mut context, &unit.entry_offsets)?; - } - - Ok(Unit { - base_id: unit.base_id, - encoding: unit.encoding, - line_program, - ranges, - locations, - entries, - root: unit.root, - }) - } - } - - impl DebuggingInformationEntry { - /// Create an entry by reading the data in the input sections. - /// - /// Does not add the entry attributes. - fn convert_entry<R: Reader<Offset = usize>>( - from: read::EntriesTreeNode<R>, - from_unit: &read::Unit<R>, - base_id: BaseId, - entries: &mut Vec<DebuggingInformationEntry>, - entry_offsets: &mut Vec<read::UnitOffset>, - entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>, - parent: Option<UnitEntryId>, - unit_id: UnitId, - ) -> ConvertResult<UnitEntryId> { - let from_entry = from.entry(); - let id = DebuggingInformationEntry::new(base_id, entries, parent, from_entry.tag()); - let offset = from_entry.offset(); - entry_offsets.push(offset); - entry_ids.insert(offset.to_unit_section_offset(from_unit), (unit_id, id)); - - let mut from_children = from.children(); - while let Some(from_child) = from_children.next()? { - DebuggingInformationEntry::convert_entry( - from_child, - from_unit, - base_id, - entries, - entry_offsets, - entry_ids, - Some(id), - unit_id, - )?; - } - Ok(id) - } - - /// Create an entry's attributes by reading the data in the input sections. - fn convert_attributes<R: Reader<Offset = usize>>( - &mut self, - context: &mut ConvertUnitContext<R>, - entry_offsets: &[read::UnitOffset], - ) -> ConvertResult<()> { - let offset = entry_offsets[self.id.index]; - let from = context.unit.entry(offset)?; - let mut from_attrs = from.attrs(); - while let Some(from_attr) = from_attrs.next()? { - if from_attr.name() == constants::DW_AT_sibling { - // This may point to a null entry, so we have to treat it differently. - self.set_sibling(true); - } else if let Some(attr) = Attribute::from(context, &from_attr)? { - self.set(attr.name, attr.value); - } - } - Ok(()) - } - } - - impl Attribute { - /// Create an attribute by reading the data in the given sections. - pub(crate) fn from<R: Reader<Offset = usize>>( - context: &mut ConvertUnitContext<R>, - from: &read::Attribute<R>, - ) -> ConvertResult<Option<Attribute>> { - let value = AttributeValue::from(context, from.value())?; - Ok(value.map(|value| Attribute { - name: from.name(), - value, - })) - } - } - - impl AttributeValue { - /// Create an attribute value by reading the data in the given sections. - pub(crate) fn from<R: Reader<Offset = usize>>( - context: &mut ConvertUnitContext<R>, - from: read::AttributeValue<R>, - ) -> ConvertResult<Option<AttributeValue>> { - let to = match from { - read::AttributeValue::Addr(val) => match (context.convert_address)(val) { - Some(val) => AttributeValue::Address(val), - None => return Err(ConvertError::InvalidAddress), - }, - read::AttributeValue::Block(r) => AttributeValue::Block(r.to_slice()?.into()), - read::AttributeValue::Data1(val) => AttributeValue::Data1(val), - read::AttributeValue::Data2(val) => AttributeValue::Data2(val), - read::AttributeValue::Data4(val) => AttributeValue::Data4(val), - read::AttributeValue::Data8(val) => AttributeValue::Data8(val), - read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val), - read::AttributeValue::Udata(val) => AttributeValue::Udata(val), - read::AttributeValue::Exprloc(expression) => { - let expression = Expression::from( - expression, - context.unit.encoding(), - Some(context.dwarf), - Some(context.unit), - Some(context.entry_ids), - context.convert_address, - )?; - AttributeValue::Exprloc(expression) - } - // TODO: it would be nice to preserve the flag form. - read::AttributeValue::Flag(val) => AttributeValue::Flag(val), - read::AttributeValue::DebugAddrBase(_base) => { - // We convert all address indices to addresses, - // so this is unneeded. - return Ok(None); - } - read::AttributeValue::DebugAddrIndex(index) => { - let val = context.dwarf.address(context.unit, index)?; - match (context.convert_address)(val) { - Some(val) => AttributeValue::Address(val), - None => return Err(ConvertError::InvalidAddress), - } - } - read::AttributeValue::UnitRef(val) => { - if !context.unit.header.is_valid_offset(val) { - return Err(ConvertError::InvalidUnitRef); - } - let id = context - .entry_ids - .get(&val.to_unit_section_offset(context.unit)) - .ok_or(ConvertError::InvalidUnitRef)?; - AttributeValue::UnitRef(id.1) - } - read::AttributeValue::DebugInfoRef(val) => { - // TODO: support relocation of this value - let id = context - .entry_ids - .get(&UnitSectionOffset::DebugInfoOffset(val)) - .ok_or(ConvertError::InvalidDebugInfoRef)?; - AttributeValue::DebugInfoRef(Reference::Entry(id.0, id.1)) - } - read::AttributeValue::DebugInfoRefSup(val) => AttributeValue::DebugInfoRefSup(val), - read::AttributeValue::DebugLineRef(val) => { - // There should only be the line program in the CU DIE which we've already - // converted, so check if it matches that. - if Some(val) == context.line_program_offset { - AttributeValue::LineProgramRef - } else { - return Err(ConvertError::InvalidLineRef); - } - } - read::AttributeValue::DebugMacinfoRef(val) => AttributeValue::DebugMacinfoRef(val), - read::AttributeValue::DebugMacroRef(val) => AttributeValue::DebugMacroRef(val), - read::AttributeValue::LocationListsRef(val) => { - let iter = context - .dwarf - .locations - .raw_locations(val, context.unit.encoding())?; - let loc_list = LocationList::from(iter, context)?; - let loc_id = context.locations.add(loc_list); - AttributeValue::LocationListRef(loc_id) - } - read::AttributeValue::DebugLocListsBase(_base) => { - // We convert all location list indices to offsets, - // so this is unneeded. - return Ok(None); - } - read::AttributeValue::DebugLocListsIndex(index) => { - let offset = context.dwarf.locations_offset(context.unit, index)?; - let iter = context - .dwarf - .locations - .raw_locations(offset, context.unit.encoding())?; - let loc_list = LocationList::from(iter, context)?; - let loc_id = context.locations.add(loc_list); - AttributeValue::LocationListRef(loc_id) - } - read::AttributeValue::RangeListsRef(offset) => { - let offset = context.dwarf.ranges_offset_from_raw(context.unit, offset); - let iter = context.dwarf.raw_ranges(context.unit, offset)?; - let range_list = RangeList::from(iter, context)?; - let range_id = context.ranges.add(range_list); - AttributeValue::RangeListRef(range_id) - } - read::AttributeValue::DebugRngListsBase(_base) => { - // We convert all range list indices to offsets, - // so this is unneeded. - return Ok(None); - } - read::AttributeValue::DebugRngListsIndex(index) => { - let offset = context.dwarf.ranges_offset(context.unit, index)?; - let iter = context - .dwarf - .ranges - .raw_ranges(offset, context.unit.encoding())?; - let range_list = RangeList::from(iter, context)?; - let range_id = context.ranges.add(range_list); - AttributeValue::RangeListRef(range_id) - } - read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val), - read::AttributeValue::DebugStrRef(offset) => { - let r = context.dwarf.string(offset)?; - let id = context.strings.add(r.to_slice()?); - AttributeValue::StringRef(id) - } - read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val), - read::AttributeValue::DebugStrOffsetsBase(_base) => { - // We convert all string offsets to `.debug_str` references, - // so this is unneeded. - return Ok(None); - } - read::AttributeValue::DebugStrOffsetsIndex(index) => { - let offset = context.dwarf.string_offset(context.unit, index)?; - let r = context.dwarf.string(offset)?; - let id = context.strings.add(r.to_slice()?); - AttributeValue::StringRef(id) - } - read::AttributeValue::DebugLineStrRef(offset) => { - let r = context.dwarf.line_string(offset)?; - let id = context.line_strings.add(r.to_slice()?); - AttributeValue::LineStringRef(id) - } - read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()), - read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val), - read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val), - read::AttributeValue::Endianity(val) => AttributeValue::Endianity(val), - read::AttributeValue::Accessibility(val) => AttributeValue::Accessibility(val), - read::AttributeValue::Visibility(val) => AttributeValue::Visibility(val), - read::AttributeValue::Virtuality(val) => AttributeValue::Virtuality(val), - read::AttributeValue::Language(val) => AttributeValue::Language(val), - read::AttributeValue::AddressClass(val) => AttributeValue::AddressClass(val), - read::AttributeValue::IdentifierCase(val) => AttributeValue::IdentifierCase(val), - read::AttributeValue::CallingConvention(val) => { - AttributeValue::CallingConvention(val) - } - read::AttributeValue::Inline(val) => AttributeValue::Inline(val), - read::AttributeValue::Ordering(val) => AttributeValue::Ordering(val), - read::AttributeValue::FileIndex(val) => { - if val == 0 { - // 0 means not specified, even for version 5. - AttributeValue::FileIndex(None) - } else { - match context.line_program_files.get(val as usize) { - Some(id) => AttributeValue::FileIndex(Some(*id)), - None => return Err(ConvertError::InvalidFileIndex), - } - } - } - // Should always be a more specific section reference. - read::AttributeValue::SecOffset(_) => { - return Err(ConvertError::InvalidAttributeValue); - } - read::AttributeValue::DwoId(DwoId(val)) => AttributeValue::Udata(val), - }; - Ok(Some(to)) - } - } -} - -#[cfg(test)] -#[cfg(feature = "read")] -mod tests { - use super::*; - use crate::common::{ - DebugAddrBase, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, LineEncoding, - }; - use crate::constants; - use crate::read; - use crate::write::{ - DebugLine, DebugLineStr, DebugStr, DwarfUnit, EndianVec, LineString, LineStringTable, - Location, LocationList, LocationListTable, Range, RangeList, RangeListOffsets, - RangeListTable, StringTable, - }; - use crate::LittleEndian; - use std::collections::HashMap; - use std::mem; - use std::sync::Arc; - - #[test] - fn test_unit_table() { - let mut strings = StringTable::default(); - - let mut units = UnitTable::default(); - let unit_id1 = units.add(Unit::new( - Encoding { - version: 4, - address_size: 8, - format: Format::Dwarf32, - }, - LineProgram::none(), - )); - let unit2 = units.add(Unit::new( - Encoding { - version: 2, - address_size: 4, - format: Format::Dwarf64, - }, - LineProgram::none(), - )); - let unit3 = units.add(Unit::new( - Encoding { - version: 5, - address_size: 4, - format: Format::Dwarf32, - }, - LineProgram::none(), - )); - assert_eq!(units.count(), 3); - { - let unit1 = units.get_mut(unit_id1); - assert_eq!(unit1.version(), 4); - assert_eq!(unit1.address_size(), 8); - assert_eq!(unit1.format(), Format::Dwarf32); - assert_eq!(unit1.count(), 1); - - let root_id = unit1.root(); - assert_eq!(root_id, UnitEntryId::new(unit1.base_id, 0)); - { - let root = unit1.get_mut(root_id); - assert_eq!(root.id(), root_id); - assert!(root.parent().is_none()); - assert_eq!(root.tag(), constants::DW_TAG_compile_unit); - - // Test get/get_mut - assert!(root.get(constants::DW_AT_producer).is_none()); - assert!(root.get_mut(constants::DW_AT_producer).is_none()); - let mut producer = AttributeValue::String(b"root"[..].into()); - root.set(constants::DW_AT_producer, producer.clone()); - assert_eq!(root.get(constants::DW_AT_producer), Some(&producer)); - assert_eq!(root.get_mut(constants::DW_AT_producer), Some(&mut producer)); - - // Test attrs - let mut attrs = root.attrs(); - let attr = attrs.next().unwrap(); - assert_eq!(attr.name(), constants::DW_AT_producer); - assert_eq!(attr.get(), &producer); - assert!(attrs.next().is_none()); - } - - let child1 = unit1.add(root_id, constants::DW_TAG_subprogram); - assert_eq!(child1, UnitEntryId::new(unit1.base_id, 1)); - { - let child1 = unit1.get_mut(child1); - assert_eq!(child1.parent(), Some(root_id)); - - let tmp = AttributeValue::String(b"tmp"[..].into()); - child1.set(constants::DW_AT_name, tmp.clone()); - assert_eq!(child1.get(constants::DW_AT_name), Some(&tmp)); - - // Test attrs_mut - let name = AttributeValue::StringRef(strings.add(&b"child1"[..])); - { - let attr = child1.attrs_mut().next().unwrap(); - assert_eq!(attr.name(), constants::DW_AT_name); - attr.set(name.clone()); - } - assert_eq!(child1.get(constants::DW_AT_name), Some(&name)); - } - - let child2 = unit1.add(root_id, constants::DW_TAG_subprogram); - assert_eq!(child2, UnitEntryId::new(unit1.base_id, 2)); - { - let child2 = unit1.get_mut(child2); - assert_eq!(child2.parent(), Some(root_id)); - - let tmp = AttributeValue::String(b"tmp"[..].into()); - child2.set(constants::DW_AT_name, tmp.clone()); - assert_eq!(child2.get(constants::DW_AT_name), Some(&tmp)); - - // Test replace - let name = AttributeValue::StringRef(strings.add(&b"child2"[..])); - child2.set(constants::DW_AT_name, name.clone()); - assert_eq!(child2.get(constants::DW_AT_name), Some(&name)); - } - - { - let root = unit1.get(root_id); - assert_eq!( - root.children().cloned().collect::<Vec<_>>(), - vec![child1, child2] - ); - } - } - { - let unit2 = units.get(unit2); - assert_eq!(unit2.version(), 2); - assert_eq!(unit2.address_size(), 4); - assert_eq!(unit2.format(), Format::Dwarf64); - assert_eq!(unit2.count(), 1); - - let root = unit2.root(); - assert_eq!(root, UnitEntryId::new(unit2.base_id, 0)); - let root = unit2.get(root); - assert_eq!(root.id(), UnitEntryId::new(unit2.base_id, 0)); - assert!(root.parent().is_none()); - assert_eq!(root.tag(), constants::DW_TAG_compile_unit); - } - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = strings.write(&mut sections.debug_str).unwrap(); - units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - - println!("{:?}", sections.debug_str); - println!("{:?}", sections.debug_info); - println!("{:?}", sections.debug_abbrev); - - let dwarf = read::Dwarf { - debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian), - debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian), - debug_str: read::DebugStr::new(sections.debug_str.slice(), LittleEndian), - ..Default::default() - }; - let mut read_units = dwarf.units(); - - { - let read_unit1 = read_units.next().unwrap().unwrap(); - let unit1 = units.get(unit_id1); - assert_eq!(unit1.version(), read_unit1.version()); - assert_eq!(unit1.address_size(), read_unit1.address_size()); - assert_eq!(unit1.format(), read_unit1.format()); - - let read_unit1 = dwarf.unit(read_unit1).unwrap(); - let mut read_entries = read_unit1.entries(); - - let root = unit1.get(unit1.root()); - { - let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 0); - assert_eq!(root.tag(), read_root.tag()); - assert!(read_root.has_children()); - - let producer = match root.get(constants::DW_AT_producer).unwrap() { - AttributeValue::String(ref producer) => &**producer, - otherwise => panic!("unexpected {:?}", otherwise), - }; - assert_eq!(producer, b"root"); - let read_producer = read_root - .attr_value(constants::DW_AT_producer) - .unwrap() - .unwrap(); - assert_eq!( - dwarf - .attr_string(&read_unit1, read_producer) - .unwrap() - .slice(), - producer - ); - } - - let mut children = root.children().cloned(); - - { - let child = children.next().unwrap(); - assert_eq!(child, UnitEntryId::new(unit1.base_id, 1)); - let child = unit1.get(child); - let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 1); - assert_eq!(child.tag(), read_child.tag()); - assert!(!read_child.has_children()); - - let name = match child.get(constants::DW_AT_name).unwrap() { - AttributeValue::StringRef(name) => *name, - otherwise => panic!("unexpected {:?}", otherwise), - }; - let name = strings.get(name); - assert_eq!(name, b"child1"); - let read_name = read_child - .attr_value(constants::DW_AT_name) - .unwrap() - .unwrap(); - assert_eq!( - dwarf.attr_string(&read_unit1, read_name).unwrap().slice(), - name - ); - } - - { - let child = children.next().unwrap(); - assert_eq!(child, UnitEntryId::new(unit1.base_id, 2)); - let child = unit1.get(child); - let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 0); - assert_eq!(child.tag(), read_child.tag()); - assert!(!read_child.has_children()); - - let name = match child.get(constants::DW_AT_name).unwrap() { - AttributeValue::StringRef(name) => *name, - otherwise => panic!("unexpected {:?}", otherwise), - }; - let name = strings.get(name); - assert_eq!(name, b"child2"); - let read_name = read_child - .attr_value(constants::DW_AT_name) - .unwrap() - .unwrap(); - assert_eq!( - dwarf.attr_string(&read_unit1, read_name).unwrap().slice(), - name - ); - } - - assert!(read_entries.next_dfs().unwrap().is_none()); - } - - { - let read_unit2 = read_units.next().unwrap().unwrap(); - let unit2 = units.get(unit2); - assert_eq!(unit2.version(), read_unit2.version()); - assert_eq!(unit2.address_size(), read_unit2.address_size()); - assert_eq!(unit2.format(), read_unit2.format()); - - let abbrevs = dwarf.abbreviations(&read_unit2).unwrap(); - let mut read_entries = read_unit2.entries(&abbrevs); - - { - let root = unit2.get(unit2.root()); - let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 0); - assert_eq!(root.tag(), read_root.tag()); - assert!(!read_root.has_children()); - } - - assert!(read_entries.next_dfs().unwrap().is_none()); - } - - { - let read_unit3 = read_units.next().unwrap().unwrap(); - let unit3 = units.get(unit3); - assert_eq!(unit3.version(), read_unit3.version()); - assert_eq!(unit3.address_size(), read_unit3.address_size()); - assert_eq!(unit3.format(), read_unit3.format()); - - let abbrevs = dwarf.abbreviations(&read_unit3).unwrap(); - let mut read_entries = read_unit3.entries(&abbrevs); - - { - let root = unit3.get(unit3.root()); - let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); - assert_eq!(depth, 0); - assert_eq!(root.tag(), read_root.tag()); - assert!(!read_root.has_children()); - } - - assert!(read_entries.next_dfs().unwrap().is_none()); - } - - assert!(read_units.next().unwrap().is_none()); - - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let convert_units = UnitTable::from( - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - &|address| Some(Address::Constant(address)), - ) - .unwrap(); - assert_eq!(convert_units.count(), units.count()); - - for i in 0..convert_units.count() { - let unit_id = units.id(i); - let unit = units.get(unit_id); - let convert_unit_id = convert_units.id(i); - let convert_unit = convert_units.get(convert_unit_id); - assert_eq!(convert_unit.version(), unit.version()); - assert_eq!(convert_unit.address_size(), unit.address_size()); - assert_eq!(convert_unit.format(), unit.format()); - assert_eq!(convert_unit.count(), unit.count()); - - let root = unit.get(unit.root()); - let convert_root = convert_unit.get(convert_unit.root()); - assert_eq!(convert_root.tag(), root.tag()); - for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) { - assert_eq!(convert_attr, attr); - } - } - } - - #[test] - fn test_attribute_value() { - // Create a string table and a string with a non-zero id/offset. - let mut strings = StringTable::default(); - strings.add("string one"); - let string_id = strings.add("string two"); - let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); - let debug_str_offsets = strings.write(&mut debug_str).unwrap(); - let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian); - - let mut line_strings = LineStringTable::default(); - line_strings.add("line string one"); - let line_string_id = line_strings.add("line string two"); - let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian)); - let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap(); - let read_debug_line_str = - read::DebugLineStr::from(read::EndianSlice::new(debug_line_str.slice(), LittleEndian)); - - let data = vec![1, 2, 3, 4]; - let read_data = read::EndianSlice::new(&[1, 2, 3, 4], LittleEndian); - - let mut expression = Expression::new(); - expression.op_constu(57); - let read_expression = read::Expression(read::EndianSlice::new( - &[constants::DW_OP_constu.0, 57], - LittleEndian, - )); - - let mut ranges = RangeListTable::default(); - let range_id = ranges.add(RangeList(vec![Range::StartEnd { - begin: Address::Constant(0x1234), - end: Address::Constant(0x2345), - }])); - - let mut locations = LocationListTable::default(); - let loc_id = locations.add(LocationList(vec![Location::StartEnd { - begin: Address::Constant(0x1234), - end: Address::Constant(0x2345), - data: expression.clone(), - }])); - - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let range_list_offsets = ranges.write(&mut sections, encoding).unwrap(); - let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap(); - - let read_debug_ranges = - read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian); - let read_debug_rnglists = - read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian); - - let read_debug_loc = - read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian); - let read_debug_loclists = - read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian); - - let mut units = UnitTable::default(); - let unit = units.add(Unit::new(encoding, LineProgram::none())); - let unit = units.get(unit); - let encoding = Encoding { - format, - version, - address_size, - }; - let from_unit = read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::new(&[], LittleEndian), - ); - - for &(ref name, ref value, ref expect_value) in &[ - ( - constants::DW_AT_name, - AttributeValue::Address(Address::Constant(0x1234)), - read::AttributeValue::Addr(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Block(data.clone()), - read::AttributeValue::Block(read_data), - ), - ( - constants::DW_AT_name, - AttributeValue::Data1(0x12), - read::AttributeValue::Data1(0x12), - ), - ( - constants::DW_AT_name, - AttributeValue::Data2(0x1234), - read::AttributeValue::Data2(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Data4(0x1234), - read::AttributeValue::Data4(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Data8(0x1234), - read::AttributeValue::Data8(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Sdata(0x1234), - read::AttributeValue::Sdata(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Udata(0x1234), - read::AttributeValue::Udata(0x1234), - ), - ( - constants::DW_AT_name, - AttributeValue::Exprloc(expression.clone()), - read::AttributeValue::Exprloc(read_expression), - ), - ( - constants::DW_AT_name, - AttributeValue::Flag(false), - read::AttributeValue::Flag(false), - ), - /* - ( - constants::DW_AT_name, - AttributeValue::FlagPresent, - read::AttributeValue::Flag(true), - ), - */ - ( - constants::DW_AT_name, - AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)), - read::AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)), - ), - ( - constants::DW_AT_location, - AttributeValue::LocationListRef(loc_id), - read::AttributeValue::SecOffset(loc_list_offsets.get(loc_id).0), - ), - ( - constants::DW_AT_macro_info, - AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(0x1234)), - read::AttributeValue::SecOffset(0x1234), - ), - ( - constants::DW_AT_macros, - AttributeValue::DebugMacroRef(DebugMacroOffset(0x1234)), - read::AttributeValue::SecOffset(0x1234), - ), - ( - constants::DW_AT_ranges, - AttributeValue::RangeListRef(range_id), - read::AttributeValue::SecOffset(range_list_offsets.get(range_id).0), - ), - ( - constants::DW_AT_name, - AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)), - read::AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)), - ), - ( - constants::DW_AT_name, - AttributeValue::StringRef(string_id), - read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)), - ), - ( - constants::DW_AT_name, - AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)), - read::AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)), - ), - ( - constants::DW_AT_name, - AttributeValue::LineStringRef(line_string_id), - read::AttributeValue::DebugLineStrRef( - debug_line_str_offsets.get(line_string_id), - ), - ), - ( - constants::DW_AT_name, - AttributeValue::String(data.clone()), - read::AttributeValue::String(read_data), - ), - ( - constants::DW_AT_encoding, - AttributeValue::Encoding(constants::DwAte(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_decimal_sign, - AttributeValue::DecimalSign(constants::DwDs(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_endianity, - AttributeValue::Endianity(constants::DwEnd(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_accessibility, - AttributeValue::Accessibility(constants::DwAccess(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_visibility, - AttributeValue::Visibility(constants::DwVis(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_virtuality, - AttributeValue::Virtuality(constants::DwVirtuality(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_language, - AttributeValue::Language(constants::DwLang(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_address_class, - AttributeValue::AddressClass(constants::DwAddr(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_identifier_case, - AttributeValue::IdentifierCase(constants::DwId(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_calling_convention, - AttributeValue::CallingConvention(constants::DwCc(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_ordering, - AttributeValue::Ordering(constants::DwOrd(0x12)), - read::AttributeValue::Udata(0x12), - ), - ( - constants::DW_AT_inline, - AttributeValue::Inline(constants::DwInl(0x12)), - read::AttributeValue::Udata(0x12), - ), - ][..] - { - let form = value.form(encoding).unwrap(); - let attr = Attribute { - name: *name, - value: value.clone(), - }; - - let offsets = UnitOffsets::none(); - let line_program_offset = None; - let mut debug_info_refs = Vec::new(); - let mut unit_refs = Vec::new(); - let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian)); - attr.value - .write( - &mut debug_info, - &mut debug_info_refs, - &mut unit_refs, - &unit, - &offsets, - line_program_offset, - &debug_line_str_offsets, - &debug_str_offsets, - &range_list_offsets, - &loc_list_offsets, - ) - .unwrap(); - - let spec = read::AttributeSpecification::new(*name, form, None); - let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian); - let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap(); - let read_value = &read_attr.raw_value(); - // read::AttributeValue is invariant in the lifetime of R. - // The lifetimes here are all okay, so transmute it. - let read_value = unsafe { - mem::transmute::< - &read::AttributeValue<read::EndianSlice<LittleEndian>>, - &read::AttributeValue<read::EndianSlice<LittleEndian>>, - >(read_value) - }; - assert_eq!(read_value, expect_value); - - let dwarf = read::Dwarf { - debug_str: read_debug_str.clone(), - debug_line_str: read_debug_line_str.clone(), - ranges: read::RangeLists::new(read_debug_ranges, read_debug_rnglists), - locations: read::LocationLists::new( - read_debug_loc, - read_debug_loclists, - ), - ..Default::default() - }; - - let unit = read::Unit { - header: from_unit, - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - - let mut context = convert::ConvertUnitContext { - dwarf: &dwarf, - unit: &unit, - line_strings: &mut line_strings, - strings: &mut strings, - ranges: &mut ranges, - locations: &mut locations, - convert_address: &|address| Some(Address::Constant(address)), - base_address: Address::Constant(0), - line_program_offset: None, - line_program_files: Vec::new(), - entry_ids: &HashMap::new(), - }; - - let convert_attr = - Attribute::from(&mut context, &read_attr).unwrap().unwrap(); - assert_eq!(convert_attr, attr); - } - } - } - } - } - - #[test] - fn test_unit_ref() { - let mut units = UnitTable::default(); - let unit_id1 = units.add(Unit::new( - Encoding { - version: 4, - address_size: 8, - format: Format::Dwarf32, - }, - LineProgram::none(), - )); - assert_eq!(unit_id1, units.id(0)); - let unit_id2 = units.add(Unit::new( - Encoding { - version: 2, - address_size: 4, - format: Format::Dwarf64, - }, - LineProgram::none(), - )); - assert_eq!(unit_id2, units.id(1)); - let unit1_child1 = UnitEntryId::new(units.get(unit_id1).base_id, 1); - let unit1_child2 = UnitEntryId::new(units.get(unit_id1).base_id, 2); - let unit2_child1 = UnitEntryId::new(units.get(unit_id2).base_id, 1); - let unit2_child2 = UnitEntryId::new(units.get(unit_id2).base_id, 2); - { - let unit1 = units.get_mut(unit_id1); - let root = unit1.root(); - let child_id1 = unit1.add(root, constants::DW_TAG_subprogram); - assert_eq!(child_id1, unit1_child1); - let child_id2 = unit1.add(root, constants::DW_TAG_subprogram); - assert_eq!(child_id2, unit1_child2); - { - let child1 = unit1.get_mut(child_id1); - child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2)); - } - { - let child2 = unit1.get_mut(child_id2); - child2.set( - constants::DW_AT_type, - AttributeValue::DebugInfoRef(Reference::Entry(unit_id2, unit2_child1)), - ); - } - } - { - let unit2 = units.get_mut(unit_id2); - let root = unit2.root(); - let child_id1 = unit2.add(root, constants::DW_TAG_subprogram); - assert_eq!(child_id1, unit2_child1); - let child_id2 = unit2.add(root, constants::DW_TAG_subprogram); - assert_eq!(child_id2, unit2_child2); - { - let child1 = unit2.get_mut(child_id1); - child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2)); - } - { - let child2 = unit2.get_mut(child_id2); - child2.set( - constants::DW_AT_type, - AttributeValue::DebugInfoRef(Reference::Entry(unit_id1, unit1_child1)), - ); - } - } - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - let debug_info_offsets = units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - - println!("{:?}", sections.debug_info); - println!("{:?}", sections.debug_abbrev); - - let dwarf = read::Dwarf { - debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian), - debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian), - ..Default::default() - }; - - let mut read_units = dwarf.units(); - { - let read_unit1 = read_units.next().unwrap().unwrap(); - assert_eq!( - read_unit1.offset(), - debug_info_offsets.unit(unit_id1).into() - ); - - let abbrevs = dwarf.abbreviations(&read_unit1).unwrap(); - let mut read_entries = read_unit1.entries(&abbrevs); - { - let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap(); - } - { - let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap(); - let offset = debug_info_offsets - .entry(unit_id1, unit1_child2) - .to_unit_offset(&read_unit1) - .unwrap(); - assert_eq!( - read_child1.attr_value(constants::DW_AT_type).unwrap(), - Some(read::AttributeValue::UnitRef(offset)) - ); - } - { - let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap(); - let offset = debug_info_offsets.entry(unit_id2, unit2_child1); - assert_eq!( - read_child2.attr_value(constants::DW_AT_type).unwrap(), - Some(read::AttributeValue::DebugInfoRef(offset)) - ); - } - } - { - let read_unit2 = read_units.next().unwrap().unwrap(); - assert_eq!( - read_unit2.offset(), - debug_info_offsets.unit(unit_id2).into() - ); - - let abbrevs = dwarf.abbreviations(&read_unit2).unwrap(); - let mut read_entries = read_unit2.entries(&abbrevs); - { - let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap(); - } - { - let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap(); - let offset = debug_info_offsets - .entry(unit_id2, unit2_child2) - .to_unit_offset(&read_unit2) - .unwrap(); - assert_eq!( - read_child1.attr_value(constants::DW_AT_type).unwrap(), - Some(read::AttributeValue::UnitRef(offset)) - ); - } - { - let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap(); - let offset = debug_info_offsets.entry(unit_id1, unit1_child1); - assert_eq!( - read_child2.attr_value(constants::DW_AT_type).unwrap(), - Some(read::AttributeValue::DebugInfoRef(offset)) - ); - } - } - - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let convert_units = UnitTable::from( - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - &|address| Some(Address::Constant(address)), - ) - .unwrap(); - assert_eq!(convert_units.count(), units.count()); - - for i in 0..convert_units.count() { - let unit = units.get(units.id(i)); - let convert_unit = convert_units.get(convert_units.id(i)); - assert_eq!(convert_unit.version(), unit.version()); - assert_eq!(convert_unit.address_size(), unit.address_size()); - assert_eq!(convert_unit.format(), unit.format()); - assert_eq!(convert_unit.count(), unit.count()); - - let root = unit.get(unit.root()); - let convert_root = convert_unit.get(convert_unit.root()); - assert_eq!(convert_root.tag(), root.tag()); - for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) { - assert_eq!(convert_attr, attr); - } - - let child1 = unit.get(UnitEntryId::new(unit.base_id, 1)); - let convert_child1 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 1)); - assert_eq!(convert_child1.tag(), child1.tag()); - for (convert_attr, attr) in convert_child1.attrs().zip(child1.attrs()) { - assert_eq!(convert_attr.name, attr.name); - match (convert_attr.value.clone(), attr.value.clone()) { - ( - AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)), - AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)), - ) => { - assert_eq!(convert_unit.index, unit.index); - assert_eq!(convert_entry.index, entry.index); - } - (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => { - assert_eq!(convert_id.index, id.index); - } - (convert_value, value) => assert_eq!(convert_value, value), - } - } - - let child2 = unit.get(UnitEntryId::new(unit.base_id, 2)); - let convert_child2 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 2)); - assert_eq!(convert_child2.tag(), child2.tag()); - for (convert_attr, attr) in convert_child2.attrs().zip(child2.attrs()) { - assert_eq!(convert_attr.name, attr.name); - match (convert_attr.value.clone(), attr.value.clone()) { - ( - AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)), - AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)), - ) => { - assert_eq!(convert_unit.index, unit.index); - assert_eq!(convert_entry.index, entry.index); - } - (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => { - assert_eq!(convert_id.index, id.index); - } - (convert_value, value) => assert_eq!(convert_value, value), - } - } - } - } - - #[test] - fn test_sibling() { - fn add_child( - unit: &mut Unit, - parent: UnitEntryId, - tag: constants::DwTag, - name: &str, - ) -> UnitEntryId { - let id = unit.add(parent, tag); - let child = unit.get_mut(id); - child.set(constants::DW_AT_name, AttributeValue::String(name.into())); - child.set_sibling(true); - id - } - - fn add_children(units: &mut UnitTable, unit_id: UnitId) { - let unit = units.get_mut(unit_id); - let root = unit.root(); - let child1 = add_child(unit, root, constants::DW_TAG_subprogram, "child1"); - add_child(unit, child1, constants::DW_TAG_variable, "grandchild1"); - add_child(unit, root, constants::DW_TAG_subprogram, "child2"); - add_child(unit, root, constants::DW_TAG_subprogram, "child3"); - } - - fn next_child<R: read::Reader<Offset = usize>>( - entries: &mut read::EntriesCursor<R>, - ) -> (read::UnitOffset, Option<read::UnitOffset>) { - let (_, entry) = entries.next_dfs().unwrap().unwrap(); - let offset = entry.offset(); - let sibling = - entry - .attr_value(constants::DW_AT_sibling) - .unwrap() - .map(|attr| match attr { - read::AttributeValue::UnitRef(offset) => offset, - _ => panic!("bad sibling value"), - }); - (offset, sibling) - } - - fn check_sibling<R: read::Reader<Offset = usize>>( - unit: &read::UnitHeader<R>, - debug_abbrev: &read::DebugAbbrev<R>, - ) { - let abbrevs = unit.abbreviations(debug_abbrev).unwrap(); - let mut entries = unit.entries(&abbrevs); - // root - entries.next_dfs().unwrap().unwrap(); - // child1 - let (_, sibling1) = next_child(&mut entries); - // grandchild1 - entries.next_dfs().unwrap().unwrap(); - // child2 - let (offset2, sibling2) = next_child(&mut entries); - // child3 - let (_, _) = next_child(&mut entries); - assert_eq!(sibling1, Some(offset2)); - assert_eq!(sibling2, None); - } - - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - let mut units = UnitTable::default(); - let unit_id1 = units.add(Unit::new(encoding, LineProgram::none())); - add_children(&mut units, unit_id1); - let unit_id2 = units.add(Unit::new(encoding, LineProgram::none())); - add_children(&mut units, unit_id2); - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - - println!("{:?}", sections.debug_info); - println!("{:?}", sections.debug_abbrev); - - let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian); - let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian); - let mut read_units = read_debug_info.units(); - check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev); - check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev); - } - - #[test] - fn test_line_ref() { - for &version in &[2, 3, 4, 5] { - for &address_size in &[4, 8] { - for &format in &[Format::Dwarf32, Format::Dwarf64] { - let encoding = Encoding { - format, - version, - address_size, - }; - - // The line program we'll be referencing. - let mut line_program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(b"comp_dir".to_vec()), - LineString::String(b"comp_name".to_vec()), - None, - ); - let dir = line_program.default_directory(); - let file1 = - line_program.add_file(LineString::String(b"file1".to_vec()), dir, None); - let file2 = - line_program.add_file(LineString::String(b"file2".to_vec()), dir, None); - - // Write, read, and convert the line program, so that we have the info - // required to convert the attributes. - let line_strings = DebugLineStrOffsets::none(); - let strings = DebugStrOffsets::none(); - let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); - let line_program_offset = line_program - .write(&mut debug_line, encoding, &line_strings, &strings) - .unwrap(); - let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); - let read_line_program = read_debug_line - .program( - line_program_offset, - address_size, - Some(read::EndianSlice::new(b"comp_dir", LittleEndian)), - Some(read::EndianSlice::new(b"comp_name", LittleEndian)), - ) - .unwrap(); - let dwarf = read::Dwarf::default(); - let mut convert_line_strings = LineStringTable::default(); - let mut convert_strings = StringTable::default(); - let (_, line_program_files) = LineProgram::from( - read_line_program, - &dwarf, - &mut convert_line_strings, - &mut convert_strings, - &|address| Some(Address::Constant(address)), - ) - .unwrap(); - - // Fake the unit. - let mut units = UnitTable::default(); - let unit = units.add(Unit::new(encoding, LineProgram::none())); - let unit = units.get(unit); - let from_unit = read::UnitHeader::new( - encoding, - 0, - read::UnitType::Compilation, - DebugAbbrevOffset(0), - DebugInfoOffset(0).into(), - read::EndianSlice::new(&[], LittleEndian), - ); - - for &(ref name, ref value, ref expect_value) in &[ - ( - constants::DW_AT_stmt_list, - AttributeValue::LineProgramRef, - read::AttributeValue::SecOffset(line_program_offset.0), - ), - ( - constants::DW_AT_decl_file, - AttributeValue::FileIndex(Some(file1)), - read::AttributeValue::Udata(file1.raw()), - ), - ( - constants::DW_AT_decl_file, - AttributeValue::FileIndex(Some(file2)), - read::AttributeValue::Udata(file2.raw()), - ), - ][..] - { - let mut ranges = RangeListTable::default(); - let mut locations = LocationListTable::default(); - let mut strings = StringTable::default(); - let mut line_strings = LineStringTable::default(); - - let form = value.form(encoding).unwrap(); - let attr = Attribute { - name: *name, - value: value.clone(), - }; - - let mut debug_info_refs = Vec::new(); - let mut unit_refs = Vec::new(); - let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian)); - let offsets = UnitOffsets::none(); - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let range_list_offsets = RangeListOffsets::none(); - let loc_list_offsets = LocationListOffsets::none(); - attr.value - .write( - &mut debug_info, - &mut debug_info_refs, - &mut unit_refs, - &unit, - &offsets, - Some(line_program_offset), - &debug_line_str_offsets, - &debug_str_offsets, - &range_list_offsets, - &loc_list_offsets, - ) - .unwrap(); - - let spec = read::AttributeSpecification::new(*name, form, None); - let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian); - let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap(); - let read_value = &read_attr.raw_value(); - // read::AttributeValue is invariant in the lifetime of R. - // The lifetimes here are all okay, so transmute it. - let read_value = unsafe { - mem::transmute::< - &read::AttributeValue<read::EndianSlice<LittleEndian>>, - &read::AttributeValue<read::EndianSlice<LittleEndian>>, - >(read_value) - }; - assert_eq!(read_value, expect_value); - - let unit = read::Unit { - header: from_unit, - abbreviations: Arc::new(read::Abbreviations::default()), - name: None, - comp_dir: None, - low_pc: 0, - str_offsets_base: DebugStrOffsetsBase(0), - addr_base: DebugAddrBase(0), - loclists_base: DebugLocListsBase(0), - rnglists_base: DebugRngListsBase(0), - line_program: None, - dwo_id: None, - }; - - let mut context = convert::ConvertUnitContext { - dwarf: &dwarf, - unit: &unit, - line_strings: &mut line_strings, - strings: &mut strings, - ranges: &mut ranges, - locations: &mut locations, - convert_address: &|address| Some(Address::Constant(address)), - base_address: Address::Constant(0), - line_program_offset: Some(line_program_offset), - line_program_files: line_program_files.clone(), - entry_ids: &HashMap::new(), - }; - - let convert_attr = - Attribute::from(&mut context, &read_attr).unwrap().unwrap(); - assert_eq!(convert_attr, attr); - } - } - } - } - } - - #[test] - fn test_line_program_used() { - for used in vec![false, true] { - let encoding = Encoding { - format: Format::Dwarf32, - version: 5, - address_size: 8, - }; - - let line_program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::String(b"comp_dir".to_vec()), - LineString::String(b"comp_name".to_vec()), - None, - ); - - let mut unit = Unit::new(encoding, line_program); - let file_id = if used { Some(FileId::new(0)) } else { None }; - let root = unit.root(); - unit.get_mut(root).set( - constants::DW_AT_decl_file, - AttributeValue::FileIndex(file_id), - ); - - let mut units = UnitTable::default(); - units.add(unit); - - let debug_line_str_offsets = DebugLineStrOffsets::none(); - let debug_str_offsets = DebugStrOffsets::none(); - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - units - .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) - .unwrap(); - assert_eq!(!used, sections.debug_line.slice().is_empty()); - } - } - - #[test] - fn test_delete_child() { - fn set_name(unit: &mut Unit, id: UnitEntryId, name: &str) { - let entry = unit.get_mut(id); - entry.set(constants::DW_AT_name, AttributeValue::String(name.into())); - } - fn check_name<R: read::Reader>( - entry: &read::DebuggingInformationEntry<R>, - debug_str: &read::DebugStr<R>, - name: &str, - ) { - let name_attr = entry.attr(constants::DW_AT_name).unwrap().unwrap(); - let entry_name = name_attr.string_value(debug_str).unwrap(); - let entry_name_str = entry_name.to_string().unwrap(); - assert_eq!(entry_name_str, name); - } - let encoding = Encoding { - format: Format::Dwarf32, - version: 4, - address_size: 8, - }; - let mut dwarf = DwarfUnit::new(encoding); - let root = dwarf.unit.root(); - - // Add and delete entries in the root unit - let child1 = dwarf.unit.add(root, constants::DW_TAG_subprogram); - set_name(&mut dwarf.unit, child1, "child1"); - let grandchild1 = dwarf.unit.add(child1, constants::DW_TAG_variable); - set_name(&mut dwarf.unit, grandchild1, "grandchild1"); - let child2 = dwarf.unit.add(root, constants::DW_TAG_subprogram); - set_name(&mut dwarf.unit, child2, "child2"); - // This deletes both `child1` and its child `grandchild1` - dwarf.unit.get_mut(root).delete_child(child1); - let child3 = dwarf.unit.add(root, constants::DW_TAG_subprogram); - set_name(&mut dwarf.unit, child3, "child3"); - let child4 = dwarf.unit.add(root, constants::DW_TAG_subprogram); - set_name(&mut dwarf.unit, child4, "child4"); - let grandchild4 = dwarf.unit.add(child4, constants::DW_TAG_variable); - set_name(&mut dwarf.unit, grandchild4, "grandchild4"); - dwarf.unit.get_mut(child4).delete_child(grandchild4); - - let mut sections = Sections::new(EndianVec::new(LittleEndian)); - - // Write DWARF data which should only include `child2`, `child3` and `child4` - dwarf.write(&mut sections).unwrap(); - - let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian); - let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian); - let read_debug_str = read::DebugStr::new(sections.debug_str.slice(), LittleEndian); - let read_unit = read_debug_info.units().next().unwrap().unwrap(); - let abbrevs = read_unit.abbreviations(&read_debug_abbrev).unwrap(); - let mut entries = read_unit.entries(&abbrevs); - // root - entries.next_dfs().unwrap().unwrap(); - // child2 - let (_, read_child2) = entries.next_dfs().unwrap().unwrap(); - check_name(read_child2, &read_debug_str, "child2"); - // child3 - let (_, read_child3) = entries.next_dfs().unwrap().unwrap(); - check_name(read_child3, &read_debug_str, "child3"); - // child4 - let (_, read_child4) = entries.next_dfs().unwrap().unwrap(); - check_name(read_child4, &read_debug_str, "child4"); - // There should be no more entries - assert!(entries.next_dfs().unwrap().is_none()); - } -} diff --git a/vendor/gimli/src/write/writer.rs b/vendor/gimli/src/write/writer.rs deleted file mode 100644 index 1ce3641..0000000 --- a/vendor/gimli/src/write/writer.rs +++ /dev/null @@ -1,494 +0,0 @@ -use crate::common::{Format, SectionId}; -use crate::constants; -use crate::endianity::Endianity; -use crate::leb128; -use crate::write::{Address, Error, Result}; - -/// A trait for writing the data to a DWARF section. -/// -/// All write operations append to the section unless otherwise specified. -#[allow(clippy::len_without_is_empty)] -pub trait Writer { - /// The endianity of bytes that are written. - type Endian: Endianity; - - /// Return the endianity of bytes that are written. - fn endian(&self) -> Self::Endian; - - /// Return the current section length. - /// - /// This may be used as an offset for future `write_at` calls. - fn len(&self) -> usize; - - /// Write a slice. - fn write(&mut self, bytes: &[u8]) -> Result<()>; - - /// Write a slice at a given offset. - /// - /// The write must not extend past the current section length. - fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()>; - - /// Write an address. - /// - /// If the writer supports relocations, then it must provide its own implementation - /// of this method. - // TODO: use write_reference instead? - fn write_address(&mut self, address: Address, size: u8) -> Result<()> { - match address { - Address::Constant(val) => self.write_udata(val, size), - Address::Symbol { .. } => Err(Error::InvalidAddress), - } - } - - /// Write an address with a `.eh_frame` pointer encoding. - /// - /// The given size is only used for `DW_EH_PE_absptr` formats. - /// - /// If the writer supports relocations, then it must provide its own implementation - /// of this method. - fn write_eh_pointer( - &mut self, - address: Address, - eh_pe: constants::DwEhPe, - size: u8, - ) -> Result<()> { - match address { - Address::Constant(val) => { - // Indirect doesn't matter here. - let val = match eh_pe.application() { - constants::DW_EH_PE_absptr => val, - constants::DW_EH_PE_pcrel => { - // TODO: better handling of sign - let offset = self.len() as u64; - val.wrapping_sub(offset) - } - _ => { - return Err(Error::UnsupportedPointerEncoding(eh_pe)); - } - }; - self.write_eh_pointer_data(val, eh_pe.format(), size) - } - Address::Symbol { .. } => Err(Error::InvalidAddress), - } - } - - /// Write a value with a `.eh_frame` pointer format. - /// - /// The given size is only used for `DW_EH_PE_absptr` formats. - /// - /// This must not be used directly for values that may require relocation. - fn write_eh_pointer_data( - &mut self, - val: u64, - format: constants::DwEhPe, - size: u8, - ) -> Result<()> { - match format { - constants::DW_EH_PE_absptr => self.write_udata(val, size), - constants::DW_EH_PE_uleb128 => self.write_uleb128(val), - constants::DW_EH_PE_udata2 => self.write_udata(val, 2), - constants::DW_EH_PE_udata4 => self.write_udata(val, 4), - constants::DW_EH_PE_udata8 => self.write_udata(val, 8), - constants::DW_EH_PE_sleb128 => self.write_sleb128(val as i64), - constants::DW_EH_PE_sdata2 => self.write_sdata(val as i64, 2), - constants::DW_EH_PE_sdata4 => self.write_sdata(val as i64, 4), - constants::DW_EH_PE_sdata8 => self.write_sdata(val as i64, 8), - _ => Err(Error::UnsupportedPointerEncoding(format)), - } - } - - /// Write an offset that is relative to the start of the given section. - /// - /// If the writer supports relocations, then it must provide its own implementation - /// of this method. - fn write_offset(&mut self, val: usize, _section: SectionId, size: u8) -> Result<()> { - self.write_udata(val as u64, size) - } - - /// Write an offset that is relative to the start of the given section. - /// - /// If the writer supports relocations, then it must provide its own implementation - /// of this method. - fn write_offset_at( - &mut self, - offset: usize, - val: usize, - _section: SectionId, - size: u8, - ) -> Result<()> { - self.write_udata_at(offset, val as u64, size) - } - - /// Write a reference to a symbol. - /// - /// If the writer supports symbols, then it must provide its own implementation - /// of this method. - fn write_reference(&mut self, _symbol: usize, _size: u8) -> Result<()> { - Err(Error::InvalidReference) - } - - /// Write a u8. - fn write_u8(&mut self, val: u8) -> Result<()> { - let bytes = [val]; - self.write(&bytes) - } - - /// Write a u16. - fn write_u16(&mut self, val: u16) -> Result<()> { - let mut bytes = [0; 2]; - self.endian().write_u16(&mut bytes, val); - self.write(&bytes) - } - - /// Write a u32. - fn write_u32(&mut self, val: u32) -> Result<()> { - let mut bytes = [0; 4]; - self.endian().write_u32(&mut bytes, val); - self.write(&bytes) - } - - /// Write a u64. - fn write_u64(&mut self, val: u64) -> Result<()> { - let mut bytes = [0; 8]; - self.endian().write_u64(&mut bytes, val); - self.write(&bytes) - } - - /// Write a u8 at the given offset. - fn write_u8_at(&mut self, offset: usize, val: u8) -> Result<()> { - let bytes = [val]; - self.write_at(offset, &bytes) - } - - /// Write a u16 at the given offset. - fn write_u16_at(&mut self, offset: usize, val: u16) -> Result<()> { - let mut bytes = [0; 2]; - self.endian().write_u16(&mut bytes, val); - self.write_at(offset, &bytes) - } - - /// Write a u32 at the given offset. - fn write_u32_at(&mut self, offset: usize, val: u32) -> Result<()> { - let mut bytes = [0; 4]; - self.endian().write_u32(&mut bytes, val); - self.write_at(offset, &bytes) - } - - /// Write a u64 at the given offset. - fn write_u64_at(&mut self, offset: usize, val: u64) -> Result<()> { - let mut bytes = [0; 8]; - self.endian().write_u64(&mut bytes, val); - self.write_at(offset, &bytes) - } - - /// Write unsigned data of the given size. - /// - /// Returns an error if the value is too large for the size. - /// This must not be used directly for values that may require relocation. - fn write_udata(&mut self, val: u64, size: u8) -> Result<()> { - match size { - 1 => { - let write_val = val as u8; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u8(write_val) - } - 2 => { - let write_val = val as u16; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u16(write_val) - } - 4 => { - let write_val = val as u32; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u32(write_val) - } - 8 => self.write_u64(val), - otherwise => Err(Error::UnsupportedWordSize(otherwise)), - } - } - - /// Write signed data of the given size. - /// - /// Returns an error if the value is too large for the size. - /// This must not be used directly for values that may require relocation. - fn write_sdata(&mut self, val: i64, size: u8) -> Result<()> { - match size { - 1 => { - let write_val = val as i8; - if val != i64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u8(write_val as u8) - } - 2 => { - let write_val = val as i16; - if val != i64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u16(write_val as u16) - } - 4 => { - let write_val = val as i32; - if val != i64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u32(write_val as u32) - } - 8 => self.write_u64(val as u64), - otherwise => Err(Error::UnsupportedWordSize(otherwise)), - } - } - - /// Write a word of the given size at the given offset. - /// - /// Returns an error if the value is too large for the size. - /// This must not be used directly for values that may require relocation. - fn write_udata_at(&mut self, offset: usize, val: u64, size: u8) -> Result<()> { - match size { - 1 => { - let write_val = val as u8; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u8_at(offset, write_val) - } - 2 => { - let write_val = val as u16; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u16_at(offset, write_val) - } - 4 => { - let write_val = val as u32; - if val != u64::from(write_val) { - return Err(Error::ValueTooLarge); - } - self.write_u32_at(offset, write_val) - } - 8 => self.write_u64_at(offset, val), - otherwise => Err(Error::UnsupportedWordSize(otherwise)), - } - } - - /// Write an unsigned LEB128 encoded integer. - fn write_uleb128(&mut self, val: u64) -> Result<()> { - let mut bytes = [0u8; 10]; - // bytes is long enough so this will never fail. - let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); - self.write(&bytes[..len]) - } - - /// Read an unsigned LEB128 encoded integer. - fn write_sleb128(&mut self, val: i64) -> Result<()> { - let mut bytes = [0u8; 10]; - // bytes is long enough so this will never fail. - let len = leb128::write::signed(&mut { &mut bytes[..] }, val).unwrap(); - self.write(&bytes[..len]) - } - - /// Write an initial length according to the given DWARF format. - /// - /// This will only write a length of zero, since the length isn't - /// known yet, and a subsequent call to `write_initial_length_at` - /// will write the actual length. - fn write_initial_length(&mut self, format: Format) -> Result<InitialLengthOffset> { - if format == Format::Dwarf64 { - self.write_u32(0xffff_ffff)?; - } - let offset = InitialLengthOffset(self.len()); - self.write_udata(0, format.word_size())?; - Ok(offset) - } - - /// Write an initial length at the given offset according to the given DWARF format. - /// - /// `write_initial_length` must have previously returned the offset. - fn write_initial_length_at( - &mut self, - offset: InitialLengthOffset, - length: u64, - format: Format, - ) -> Result<()> { - self.write_udata_at(offset.0, length, format.word_size()) - } -} - -/// The offset at which an initial length should be written. -#[derive(Debug, Clone, Copy)] -pub struct InitialLengthOffset(usize); - -#[cfg(test)] -mod tests { - use super::*; - use crate::write; - use crate::{BigEndian, LittleEndian}; - use std::{i64, u64}; - - #[test] - fn test_writer() { - let mut w = write::EndianVec::new(LittleEndian); - w.write_address(Address::Constant(0x1122_3344), 4).unwrap(); - assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); - assert_eq!( - w.write_address( - Address::Symbol { - symbol: 0, - addend: 0 - }, - 4 - ), - Err(Error::InvalidAddress) - ); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_offset(0x1122_3344, SectionId::DebugInfo, 4) - .unwrap(); - assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); - w.write_offset_at(1, 0x5566, SectionId::DebugInfo, 2) - .unwrap(); - assert_eq!(w.slice(), &[0x44, 0x66, 0x55, 0x11]); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_u8(0x11).unwrap(); - w.write_u16(0x2233).unwrap(); - w.write_u32(0x4455_6677).unwrap(); - w.write_u64(0x8081_8283_8485_8687).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x11, - 0x33, 0x22, - 0x77, 0x66, 0x55, 0x44, - 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, - ]); - w.write_u8_at(14, 0x11).unwrap(); - w.write_u16_at(12, 0x2233).unwrap(); - w.write_u32_at(8, 0x4455_6677).unwrap(); - w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, - 0x77, 0x66, 0x55, 0x44, - 0x33, 0x22, - 0x11, - ]); - - let mut w = write::EndianVec::new(BigEndian); - w.write_u8(0x11).unwrap(); - w.write_u16(0x2233).unwrap(); - w.write_u32(0x4455_6677).unwrap(); - w.write_u64(0x8081_8283_8485_8687).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x11, - 0x22, 0x33, - 0x44, 0x55, 0x66, 0x77, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - ]); - w.write_u8_at(14, 0x11).unwrap(); - w.write_u16_at(12, 0x2233).unwrap(); - w.write_u32_at(8, 0x4455_6677).unwrap(); - w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x44, 0x55, 0x66, 0x77, - 0x22, 0x33, - 0x11, - ]); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_udata(0x11, 1).unwrap(); - w.write_udata(0x2233, 2).unwrap(); - w.write_udata(0x4455_6677, 4).unwrap(); - w.write_udata(0x8081_8283_8485_8687, 8).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x11, - 0x33, 0x22, - 0x77, 0x66, 0x55, 0x44, - 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, - ]); - assert_eq!(w.write_udata(0x100, 1), Err(Error::ValueTooLarge)); - assert_eq!(w.write_udata(0x1_0000, 2), Err(Error::ValueTooLarge)); - assert_eq!(w.write_udata(0x1_0000_0000, 4), Err(Error::ValueTooLarge)); - assert_eq!(w.write_udata(0x00, 3), Err(Error::UnsupportedWordSize(3))); - w.write_udata_at(14, 0x11, 1).unwrap(); - w.write_udata_at(12, 0x2233, 2).unwrap(); - w.write_udata_at(8, 0x4455_6677, 4).unwrap(); - w.write_udata_at(0, 0x8081_8283_8485_8687, 8).unwrap(); - #[rustfmt::skip] - assert_eq!(w.slice(), &[ - 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, - 0x77, 0x66, 0x55, 0x44, - 0x33, 0x22, - 0x11, - ]); - assert_eq!(w.write_udata_at(0, 0x100, 1), Err(Error::ValueTooLarge)); - assert_eq!(w.write_udata_at(0, 0x1_0000, 2), Err(Error::ValueTooLarge)); - assert_eq!( - w.write_udata_at(0, 0x1_0000_0000, 4), - Err(Error::ValueTooLarge) - ); - assert_eq!( - w.write_udata_at(0, 0x00, 3), - Err(Error::UnsupportedWordSize(3)) - ); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_uleb128(0).unwrap(); - assert_eq!(w.slice(), &[0]); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_uleb128(u64::MAX).unwrap(); - assert_eq!( - w.slice(), - &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1] - ); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_sleb128(0).unwrap(); - assert_eq!(w.slice(), &[0]); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_sleb128(i64::MAX).unwrap(); - assert_eq!( - w.slice(), - &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0] - ); - - let mut w = write::EndianVec::new(LittleEndian); - w.write_sleb128(i64::MIN).unwrap(); - assert_eq!( - w.slice(), - &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f] - ); - - let mut w = write::EndianVec::new(LittleEndian); - let offset = w.write_initial_length(Format::Dwarf32).unwrap(); - assert_eq!(w.slice(), &[0, 0, 0, 0]); - w.write_initial_length_at(offset, 0x1122_3344, Format::Dwarf32) - .unwrap(); - assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); - assert_eq!( - w.write_initial_length_at(offset, 0x1_0000_0000, Format::Dwarf32), - Err(Error::ValueTooLarge) - ); - - let mut w = write::EndianVec::new(LittleEndian); - let offset = w.write_initial_length(Format::Dwarf64).unwrap(); - assert_eq!(w.slice(), &[0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0]); - w.write_initial_length_at(offset, 0x1122_3344_5566_7788, Format::Dwarf64) - .unwrap(); - assert_eq!( - w.slice(), - &[0xff, 0xff, 0xff, 0xff, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11] - ); - } -} |