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,