Skip to content

Commit

Permalink
Clear up confusion on elf32 vs elf64 notes which in fact are the same
Browse files Browse the repository at this point in the history
At least linux, freebsd and llvm headers define Elf32_Nhdr:
  Elf32_Word n_namesz;
  Elf32_Word n_descsz;
  Elf32_Word n_type;

and Elf64_Nhdr as:
  Elf64_Word n_namesz;
  Elf64_Word n_descsz;
  Elf64_Word n_type;

Both Elf32_Word and Elf64_Word correspond to u32 (Half, Word, Xword
types are the same for Elf32 and Elf64, while types such as Addr and Off
differ).

Note (no pun intended) that this contradicts
  System V Application Binary Interface - DRAFT - 24 April 2001
which says:

> Note Section
> ...
> The note information in sections and program header elements holds a
> variable amount of entries. In 64-bit objects (files with
> e_ident[EI_CLASS] equal to ELFCLASS64), each entry is an array of
> 8-byte words in the format of the target processor. In 32-bit objects
> (files with e_ident[EI_CLASS] equal to ELFCLASS32), each entry is an
> array of 4-byte words in the format of the target processor. Labels
> appear below to help explain note information organization, but they
> are not part of the specification.

But according to
  SysTools.Elf from GHC
  https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/SysTools/Elf.hs#L81
"nobody" does that:

> In practice, for almost all platforms namesz, descz and type fields
> are 4-byte words for both 32-bit and 64-bit objects (see elf.h and
> readelf source code).
>
> The only exception in readelf source code is for IA_64 machines with
> OpenVMS OS
  • Loading branch information
wanders committed Jan 16, 2024
1 parent 5634812 commit 6d803ba
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 123 deletions.
114 changes: 57 additions & 57 deletions src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,125 +1153,125 @@ pub const ELF_NOTE_GNU: &[u8] = b"GNU\0";
// Note header descriptor types constants (n_type)

/// Contains copy of prstatus struct
pub const NT_PRSTATUS: u64 = 1;
pub const NT_PRSTATUS: u32 = 1;
/// Contains copy of fpregset struct
pub const NT_PRFPREG: u64 = 2;
pub const NT_PRFPREG: u32 = 2;
/// Contains copy of fpregset struct
pub const NT_FPREGSET: u64 = 2;
pub const NT_FPREGSET: u32 = 2;
/// Contains copy of prpsinfo struct
pub const NT_PRPSINFO: u64 = 3;
pub const NT_PRPSINFO: u32 = 3;
/// Contains copy of prxregset struct
pub const NT_PRXREG: u64 = 4;
pub const NT_PRXREG: u32 = 4;
/// Contains copy of task structure
pub const NT_TASKSTRUCT: u64 = 4;
pub const NT_TASKSTRUCT: u32 = 4;
/// String from sysinfo(SI_PLATFORM)
pub const NT_PLATFORM: u64 = 5;
pub const NT_PLATFORM: u32 = 5;
/// Contains copy of auxv array
pub const NT_AUXV: u64 = 6;
pub const NT_AUXV: u32 = 6;
/// Contains copy of gwindows struct
pub const NT_GWINDOWS: u64 = 7;
pub const NT_GWINDOWS: u32 = 7;
/// Contains copy of asrset struct
pub const NT_ASRS: u64 = 8;
pub const NT_ASRS: u32 = 8;
/// Contains copy of pstatus struct
pub const NT_PSTATUS: u64 = 10;
pub const NT_PSTATUS: u32 = 10;
/// Contains copy of psinfo struct
pub const NT_PSINFO: u64 = 13;
pub const NT_PSINFO: u32 = 13;
/// Contains copy of prcred struct
pub const NT_PRCRED: u64 = 14;
pub const NT_PRCRED: u32 = 14;
/// Contains copy of utsname struct
pub const NT_UTSNAME: u64 = 15;
pub const NT_UTSNAME: u32 = 15;
/// Contains copy of lwpstatus struct
pub const NT_LWPSTATUS: u64 = 16;
pub const NT_LWPSTATUS: u32 = 16;
/// Contains copy of lwpinfo struct
pub const NT_LWPSINFO: u64 = 17;
pub const NT_LWPSINFO: u32 = 17;
/// Contains copy of fprxregset struct
pub const NT_PRFPXREG: u64 = 20;
pub const NT_PRFPXREG: u32 = 20;
/// Contains copy of siginfo_t, size might increase
pub const NT_SIGINFO: u64 = 0x53494749;
pub const NT_SIGINFO: u32 = 0x53494749;
/// Contains information about mapped files
pub const NT_FILE: u64 = 0x46494c45;
pub const NT_FILE: u32 = 0x46494c45;
/// Contains copy of user_fxsr_struct
pub const NT_PRXFPREG: u64 = 0x46e62b7f;
pub const NT_PRXFPREG: u32 = 0x46e62b7f;
/// /// PowerPC Altivec/VMX registers
pub const NT_PPC_VMX: u64 = 0x100;
pub const NT_PPC_VMX: u32 = 0x100;
/// PowerPC SPE/EVR registers
pub const NT_PPC_SPE: u64 = 0x101;
pub const NT_PPC_SPE: u32 = 0x101;
/// PowerPC VSX registers
pub const NT_PPC_VSX: u64 = 0x102;
pub const NT_PPC_VSX: u32 = 0x102;
/// Target Address Register
pub const NT_PPC_TAR: u64 = 0x103;
pub const NT_PPC_TAR: u32 = 0x103;
/// Program Priority Register
pub const NT_PPC_PPR: u64 = 0x104;
pub const NT_PPC_PPR: u32 = 0x104;
/// Data Stream Control Register
pub const NT_PPC_DSCR: u64 = 0x105;
pub const NT_PPC_DSCR: u32 = 0x105;
/// Event Based Branch Registers
pub const NT_PPC_EBB: u64 = 0x106;
pub const NT_PPC_EBB: u32 = 0x106;
/// Performance Monitor Registers
pub const NT_PPC_PMU: u64 = 0x107;
pub const NT_PPC_PMU: u32 = 0x107;
/// TM checkpointed GPR Registers
pub const NT_PPC_TM_CGPR: u64 = 0x108;
pub const NT_PPC_TM_CGPR: u32 = 0x108;
/// TM checkpointed FPR Registers
pub const NT_PPC_TM_CFPR: u64 = 0x109;
pub const NT_PPC_TM_CFPR: u32 = 0x109;
/// TM checkpointed VMX Registers
pub const NT_PPC_TM_CVMX: u64 = 0x10a;
pub const NT_PPC_TM_CVMX: u32 = 0x10a;
/// TM checkpointed VSX Registers
pub const NT_PPC_TM_CVSX: u64 = 0x10b;
pub const NT_PPC_TM_CVSX: u32 = 0x10b;
/// TM Special Purpose Registers
pub const NT_PPC_TM_SPR: u64 = 0x10c;
pub const NT_PPC_TM_SPR: u32 = 0x10c;
/// TM checkpointed Target Address Register
pub const NT_PPC_TM_CTAR: u64 = 0x10d;
pub const NT_PPC_TM_CTAR: u32 = 0x10d;
/// TM checkpointed Program Priority Register
pub const NT_PPC_TM_CPPR: u64 = 0x10e;
pub const NT_PPC_TM_CPPR: u32 = 0x10e;
/// TM checkpointed Data Stream Control Register
pub const NT_PPC_TM_CDSCR: u64 = 0x10f;
pub const NT_PPC_TM_CDSCR: u32 = 0x10f;
/// Memory Protection Keys registers
pub const NT_PPC_PKEY: u64 = 0x110;
pub const NT_PPC_PKEY: u32 = 0x110;
/// i386 TLS slots (struct user_desc)
pub const NT_386_TLS: u64 = 0x200;
pub const NT_386_TLS: u32 = 0x200;
/// x86 io permission bitmap (1=deny)
pub const NT_386_IOPERM: u64 = 0x201;
pub const NT_386_IOPERM: u32 = 0x201;
/// x86 extended state using xsave
pub const NT_X86_XSTATE: u64 = 0x202;
pub const NT_X86_XSTATE: u32 = 0x202;
/// ARM VFP/NEON registers
pub const NT_ARM_VFP: u64 = 0x400;
pub const NT_ARM_VFP: u32 = 0x400;
/// ARM TLS register
pub const NT_ARM_TLS: u64 = 0x401;
pub const NT_ARM_TLS: u32 = 0x401;
/// ARM hardware breakpoint registers
pub const NT_ARM_HW_BREAK: u64 = 0x402;
pub const NT_ARM_HW_BREAK: u32 = 0x402;
/// ARM hardware watchpoint registers
pub const NT_ARM_HW_WATCH: u64 = 0x403;
pub const NT_ARM_HW_WATCH: u32 = 0x403;
/// ARM system call number
pub const NT_ARM_SYSTEM_CALL: u64 = 0x404;
pub const NT_ARM_SYSTEM_CALL: u32 = 0x404;
/// ARM Scalable Vector Extension registers
pub const NT_ARM_SVE: u64 = 0x405;
pub const NT_ARM_SVE: u32 = 0x405;
/// ARM pointer authentication code masks
pub const NT_ARM_PAC_MASK: u64 = 0x406;
pub const NT_ARM_PAC_MASK: u32 = 0x406;
/// ARM pointer authentication address keys
pub const NT_ARM_PACA_KEYS: u64 = 0x407;
pub const NT_ARM_PACA_KEYS: u32 = 0x407;
/// ARM pointer authentication generic key
pub const NT_ARM_PACG_KEYS: u64 = 0x408;
pub const NT_ARM_PACG_KEYS: u32 = 0x408;
/// AArch64 tagged address control.
pub const NT_ARM_TAGGED_ADDR_CTRL: u64 = 0x409;
pub const NT_ARM_TAGGED_ADDR_CTRL: u32 = 0x409;
/// AArch64 pointer authentication enabled keys
pub const NT_ARM_PAC_ENABLED_KEYS: u64 = 0x40a;
pub const NT_ARM_PAC_ENABLED_KEYS: u32 = 0x40a;
/// Vmcore Device Dump Note
pub const NT_VMCOREDD: u64 = 0x700;
pub const NT_VMCOREDD: u32 = 0x700;

/// ABI information
/// The descriptor consists of words:
/// word 0: OS descriptor
/// word 1: major version of the ABI
/// word 2: minor version of the ABI
/// word 3: subminor version of the ABI
pub const NT_GNU_ABI_TAG: u64 = 1;
pub const NT_GNU_ABI_TAG: u32 = 1;
/// Synthetic hwcap information
pub const NT_GNU_HWCAP: u64 = 2;
pub const NT_GNU_HWCAP: u32 = 2;
/// Build ID bits as generated by ld --build-id.
pub const NT_GNU_BUILD_ID: u64 = 3;
pub const NT_GNU_BUILD_ID: u32 = 3;
/// Version note generated by GNU gold containing a version string
pub const NT_GNU_GOLD_VERSION: u64 = 4;
pub const NT_GNU_GOLD_VERSION: u32 = 4;
/// Program property note which describes special handling requirements for linker and run-time loader.
pub const NT_GNU_PROPERTY_TYPE_0: u64 = 5;
pub const NT_GNU_PROPERTY_TYPE_0: u32 = 5;

// These values can appear in word 0 of an NT_GNU_ABI_TAG note section entry.
pub const ELF_NOTE_GNU_ABI_TAG_OS_LINUX: u32 = 0;
Expand Down
87 changes: 21 additions & 66 deletions src/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ impl<'data> Note<'data> {
return Err(ParseError::UnexpectedAlignment(align));
}

// It looks like clang and gcc emit 32-bit notes for 64-bit files, so we
// currently always parse all note headers as 32-bit.
let nhdr = NoteHeader::parse_at(endian, Class::ELF32, offset, data)?;
let nhdr = NoteHeader::parse_at(endian, _class, offset, data)?;

let name_start = *offset;
let name_size: usize = nhdr.n_namesz.try_into()?;
Expand Down Expand Up @@ -171,7 +169,7 @@ pub struct NoteGnuBuildId<'data>(pub &'data [u8]);
/// how to parse into more specific types.
#[derive(Debug, PartialEq, Eq)]
pub struct NoteAny<'data> {
pub n_type: u64,
pub n_type: u32,
pub name: &'data [u8],
pub desc: &'data [u8],
}
Expand Down Expand Up @@ -225,38 +223,33 @@ impl<'data, E: EndianParse> Iterator for NoteIterator<'data, E> {

#[derive(Debug, Clone, PartialEq, Eq)]
struct NoteHeader {
pub n_namesz: u64,
pub n_descsz: u64,
pub n_type: u64,
pub n_namesz: u32,
pub n_descsz: u32,
pub n_type: u32,
}

impl ParseAt for NoteHeader {
fn parse_at<E: EndianParse>(
endian: E,
class: Class,
_class: Class,
offset: &mut usize,
data: &[u8],
) -> Result<Self, ParseError> {
match class {
Class::ELF32 => Ok(NoteHeader {
n_namesz: endian.parse_u32_at(offset, data)? as u64,
n_descsz: endian.parse_u32_at(offset, data)? as u64,
n_type: endian.parse_u32_at(offset, data)? as u64,
}),
Class::ELF64 => Ok(NoteHeader {
n_namesz: endian.parse_u64_at(offset, data)?,
n_descsz: endian.parse_u64_at(offset, data)?,
n_type: endian.parse_u64_at(offset, data)?,
}),
}
/*
* Elf32_Nhdr is three Elf32_Word and Elf64_Nhdr is three
* Elf64_Word, but Elf32_Word and Elf64_Word are both u32. So
* this means that they are identical.
*/
Ok(NoteHeader {
n_namesz: endian.parse_u32_at(offset, data)? as u32,
n_descsz: endian.parse_u32_at(offset, data)? as u32,
n_type: endian.parse_u32_at(offset, data)? as u32,
})
}

#[inline]
fn size_for(class: Class) -> usize {
match class {
Class::ELF32 => 12,
Class::ELF64 => 24,
}
fn size_for(_class: Class) -> usize {
12
}
}

Expand Down Expand Up @@ -339,9 +332,9 @@ mod parse_tests {
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];

// Even though the file class is ELF64, we parse it as a 32-bit struct. gcc/clang seem to output 32-bit notes
// even though the gABI states that ELF64 files should contain 64-bit notes. Sometimes those notes are generated
// in sections with 4-byte alignment, and other times with 8-byte alignment, as specified by shdr.sh_addralign.
// Sometimes those notes are generated in sections with 4-byte
// alignment, and other times with 8-byte alignment, as
// specified by shdr.sh_addralign.
//
// See https://raw.githubusercontent.com/wiki/hjl-tools/linux-abi/linux-abi-draft.pdf
// Excerpt:
Expand Down Expand Up @@ -399,8 +392,6 @@ mod parse_tests {
];

let mut offset = 0;
// Even though the file class is ELF64, we parse it as a 32-bit struct. gcc/clang seem to output 32-bit notes
// even though the gABI states that ELF64 files should contain 64-bit notes.
let note = Note::parse_at(LittleEndian, Class::ELF64, 4, &mut offset, &data)
.expect("Failed to parse");
assert_eq!(
Expand Down Expand Up @@ -599,32 +590,6 @@ mod parse_tests {
);
}

#[test]
fn parse_nhdr64_lsb() {
test_parse_for(
LittleEndian,
Class::ELF64,
NoteHeader {
n_namesz: 0x0706050403020100,
n_descsz: 0x0F0E0D0C0B0A0908,
n_type: 0x1716151413121110,
},
);
}

#[test]
fn parse_nhdr64_msb() {
test_parse_for(
BigEndian,
Class::ELF64,
NoteHeader {
n_namesz: 0x0001020304050607,
n_descsz: 0x08090A0B0C0D0E0F,
n_type: 0x1011121314151617,
},
);
}

#[test]
fn parse_nhdr32_lsb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, NoteHeader>(LittleEndian, Class::ELF32);
Expand All @@ -634,14 +599,4 @@ mod parse_tests {
fn parse_nhdr32_msb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, NoteHeader>(BigEndian, Class::ELF32);
}

#[test]
fn parse_nhdr64_lsb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, NoteHeader>(LittleEndian, Class::ELF64);
}

#[test]
fn parse_nhdr64_msb_fuzz_too_short() {
test_parse_fuzz_too_short::<_, NoteHeader>(BigEndian, Class::ELF64);
}
}

0 comments on commit 6d803ba

Please sign in to comment.