diff --git a/SOURCES/ltrace-0.7.91-cet.patch b/SOURCES/ltrace-0.7.91-cet.patch new file mode 100644 index 0000000..a320682 --- /dev/null +++ b/SOURCES/ltrace-0.7.91-cet.patch @@ -0,0 +1,121 @@ +diff -rup a/ltrace-elf.c b/ltrace-elf.c +--- a/ltrace-elf.c 2019-02-28 17:32:49.873659818 -0500 ++++ b/ltrace-elf.c 2019-02-28 17:36:32.426779439 -0500 +@@ -639,7 +639,21 @@ ltelf_read_elf(struct ltelf *lte, const + } + } else if (shdr.sh_type == SHT_PROGBITS + || shdr.sh_type == SHT_NOBITS) { +- if (strcmp(name, ".plt") == 0) { ++ if (strcmp(name, ".plt") == 0 ++ && lte->second_plt_seen == 0) { ++ lte->plt_addr = shdr.sh_addr; ++ lte->plt_size = shdr.sh_size; ++ lte->plt_data = elf_loaddata(scn, &shdr); ++ if (lte->plt_data == NULL) ++ fprintf(stderr, ++ "Can't load .plt data\n"); ++ lte->plt_flags = shdr.sh_flags; ++ } ++ /* An Intel CET binary has two PLTs; the ++ initial PLTGOT points to the second ++ one. */ ++ else if (strcmp(name, ".plt.sec") == 0) { ++ lte->second_plt_seen = 1; + lte->plt_addr = shdr.sh_addr; + lte->plt_size = shdr.sh_size; + lte->plt_data = elf_loaddata(scn, &shdr); +diff -rup a/ltrace-elf.h b/ltrace-elf.h +--- a/ltrace-elf.h 2019-02-28 17:32:49.874660328 -0500 ++++ b/ltrace-elf.h 2019-02-28 17:36:32.428779868 -0500 +@@ -45,6 +45,7 @@ struct ltelf { + Elf_Data *dynsym; + size_t dynsym_count; + const char *dynstr; ++ int second_plt_seen; + GElf_Addr plt_addr; + GElf_Word plt_flags; + size_t plt_size; +diff -rup a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c +--- a/sysdeps/linux-gnu/x86/plt.c 2019-02-28 17:32:49.991720041 -0500 ++++ b/sysdeps/linux-gnu/x86/plt.c 2019-02-28 17:36:32.429780083 -0500 +@@ -28,18 +28,18 @@ + #include "trace.h" + + static GElf_Addr +-x86_plt_offset(uint32_t i) ++x86_plt_offset(struct ltelf *lte, uint32_t i) + { + /* Skip the first PLT entry, which contains a stub to call the + * resolver. */ +- return (i + 1) * 16; ++ return (i + (lte->second_plt_seen ? 0 : 1)) * 16; + } + + GElf_Addr + arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela) + { + uint32_t i = *VECT_ELEMENT(<e->arch.plt_map, uint32_t, ndx); +- return x86_plt_offset(i) + lte->plt_addr; ++ return x86_plt_offset(lte, i) + lte->plt_addr; + } + + void * +@@ -116,6 +116,13 @@ arch_elf_init(struct ltelf *lte, struct + * 400426: 68 00 00 00 00 pushq $0x0 + * 40042b: e9 e0 ff ff ff jmpq 400410 <_init+0x18> + * ++ * For CET binaries it is the following: ++ * ++ * 13d0: f3 0f 1e fa endbr64 ++ * 13d4: 68 27 00 00 00 pushq $0x27 <-- index ++ * 13d9: f2 e9 71 fd ff ff bnd jmpq 1150 <.plt> ++ * 13df: 90 nop ++ * + * On i386, the argument to push is an offset of relocation to + * use. The first PLT slot has an offset of 0x0, the second + * 0x8, etc. On x86_64, it's directly the index that we are +@@ -128,11 +135,33 @@ arch_elf_init(struct ltelf *lte, struct + unsigned int i, sz = vect_size(<e->plt_relocs); + for (i = 0; i < sz; ++i) { + +- GElf_Addr offset = x86_plt_offset(i); ++ GElf_Addr offset = x86_plt_offset(lte, i); ++ uint32_t reloc_arg; + + uint8_t byte; +- if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0 +- || byte != 0xff ++ if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0) ++ continue; ++ ++ ++ if (byte == 0xf3 ++ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0 ++ && byte == 0x0f ++ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0 ++ && byte == 0x1e ++ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0 ++ && byte == 0xfa ++ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0 ++ && byte == 0x68 ++ && elf_read_next_u32(lte->plt_data, ++ &offset, &reloc_arg) >= 0) ++ { ++ /* CET */ ++ fprintf(stderr, "%d: reloc_arg is %lx\n", i, (long)reloc_arg); ++ *VECT_ELEMENT(<e->arch.plt_map, unsigned int, reloc_arg) = i; ++ continue; ++ } ++ ++ if (byte != 0xff + || elf_read_next_u8(lte->plt_data, &offset, &byte) < 0 + || (byte != 0xa3 && byte != 0x25)) + continue; +@@ -140,7 +169,6 @@ arch_elf_init(struct ltelf *lte, struct + /* Skip immediate argument in the instruction. */ + offset += 4; + +- uint32_t reloc_arg; + if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0 + || byte != 0x68 + || elf_read_next_u32(lte->plt_data, diff --git a/SPECS/ltrace.spec b/SPECS/ltrace.spec index 46e6225..3bbe7bb 100644 --- a/SPECS/ltrace.spec +++ b/SPECS/ltrace.spec @@ -1,7 +1,7 @@ Summary: Tracks runtime library calls from dynamically linked executables Name: ltrace Version: 0.7.91 -Release: 27%{?dist} +Release: 28%{?dist} URL: http://ltrace.alioth.debian.org/ License: GPLv2+ Group: Development/Debuggers @@ -106,6 +106,9 @@ Patch27: ltrace-rh1423913.patch # AARCH64 large parameters and syscall testsuite fixes. Patch28: ltrace-0.7.91-aarch64-params.patch +# IA64 CET support +Patch29: ltrace-0.7.91-cet.patch + %description Ltrace is a debugging program which runs a specified command until the command exits. While the command is executing, ltrace intercepts and @@ -146,6 +149,7 @@ execution of processes. %patch26 -p1 %patch27 -p1 %patch28 -p1 +%patch29 -p1 %build autoreconf -i @@ -171,6 +175,9 @@ echo ====================TESTING END===================== %{_datadir}/ltrace %changelog +* Tue Nov 05 2019 DJ Delorie - 0.7.91-28 +- Support Intel CET PLTs (#1655368) + * Fri Jul 06 2018 DJ Delorie - 0.7.91-27 - Fix aarch64 long parameters (via $r8) support. - Make system_call_params test compare more exactly.