|
|
2e4be5 |
diff -rup a/ltrace-elf.c b/ltrace-elf.c
|
|
|
2e4be5 |
--- a/ltrace-elf.c 2019-02-28 17:32:49.873659818 -0500
|
|
|
2e4be5 |
+++ b/ltrace-elf.c 2019-02-28 17:36:32.426779439 -0500
|
|
|
2e4be5 |
@@ -639,7 +639,21 @@ ltelf_read_elf(struct ltelf *lte, const
|
|
|
2e4be5 |
}
|
|
|
2e4be5 |
} else if (shdr.sh_type == SHT_PROGBITS
|
|
|
2e4be5 |
|| shdr.sh_type == SHT_NOBITS) {
|
|
|
2e4be5 |
- if (strcmp(name, ".plt") == 0) {
|
|
|
2e4be5 |
+ if (strcmp(name, ".plt") == 0
|
|
|
2e4be5 |
+ && lte->second_plt_seen == 0) {
|
|
|
2e4be5 |
+ lte->plt_addr = shdr.sh_addr;
|
|
|
2e4be5 |
+ lte->plt_size = shdr.sh_size;
|
|
|
2e4be5 |
+ lte->plt_data = elf_loaddata(scn, &shdr);
|
|
|
2e4be5 |
+ if (lte->plt_data == NULL)
|
|
|
2e4be5 |
+ fprintf(stderr,
|
|
|
2e4be5 |
+ "Can't load .plt data\n");
|
|
|
2e4be5 |
+ lte->plt_flags = shdr.sh_flags;
|
|
|
2e4be5 |
+ }
|
|
|
2e4be5 |
+ /* An Intel CET binary has two PLTs; the
|
|
|
2e4be5 |
+ initial PLTGOT points to the second
|
|
|
2e4be5 |
+ one. */
|
|
|
2e4be5 |
+ else if (strcmp(name, ".plt.sec") == 0) {
|
|
|
2e4be5 |
+ lte->second_plt_seen = 1;
|
|
|
2e4be5 |
lte->plt_addr = shdr.sh_addr;
|
|
|
2e4be5 |
lte->plt_size = shdr.sh_size;
|
|
|
2e4be5 |
lte->plt_data = elf_loaddata(scn, &shdr);
|
|
|
2e4be5 |
diff -rup a/ltrace-elf.h b/ltrace-elf.h
|
|
|
2e4be5 |
--- a/ltrace-elf.h 2019-02-28 17:32:49.874660328 -0500
|
|
|
2e4be5 |
+++ b/ltrace-elf.h 2019-02-28 17:36:32.428779868 -0500
|
|
|
2e4be5 |
@@ -45,6 +45,7 @@ struct ltelf {
|
|
|
2e4be5 |
Elf_Data *dynsym;
|
|
|
2e4be5 |
size_t dynsym_count;
|
|
|
2e4be5 |
const char *dynstr;
|
|
|
2e4be5 |
+ int second_plt_seen;
|
|
|
2e4be5 |
GElf_Addr plt_addr;
|
|
|
2e4be5 |
GElf_Word plt_flags;
|
|
|
2e4be5 |
size_t plt_size;
|
|
|
2e4be5 |
diff -rup a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c
|
|
|
2e4be5 |
--- a/sysdeps/linux-gnu/x86/plt.c 2019-02-28 17:32:49.991720041 -0500
|
|
|
2e4be5 |
+++ b/sysdeps/linux-gnu/x86/plt.c 2019-02-28 17:36:32.429780083 -0500
|
|
|
2e4be5 |
@@ -28,18 +28,18 @@
|
|
|
2e4be5 |
#include "trace.h"
|
|
|
2e4be5 |
|
|
|
2e4be5 |
static GElf_Addr
|
|
|
2e4be5 |
-x86_plt_offset(uint32_t i)
|
|
|
2e4be5 |
+x86_plt_offset(struct ltelf *lte, uint32_t i)
|
|
|
2e4be5 |
{
|
|
|
2e4be5 |
/* Skip the first PLT entry, which contains a stub to call the
|
|
|
2e4be5 |
* resolver. */
|
|
|
2e4be5 |
- return (i + 1) * 16;
|
|
|
2e4be5 |
+ return (i + (lte->second_plt_seen ? 0 : 1)) * 16;
|
|
|
2e4be5 |
}
|
|
|
2e4be5 |
|
|
|
2e4be5 |
GElf_Addr
|
|
|
2e4be5 |
arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
|
|
|
2e4be5 |
{
|
|
|
2e4be5 |
uint32_t i = *VECT_ELEMENT(<e->arch.plt_map, uint32_t, ndx);
|
|
|
2e4be5 |
- return x86_plt_offset(i) + lte->plt_addr;
|
|
|
2e4be5 |
+ return x86_plt_offset(lte, i) + lte->plt_addr;
|
|
|
2e4be5 |
}
|
|
|
2e4be5 |
|
|
|
2e4be5 |
void *
|
|
|
2e4be5 |
@@ -116,6 +116,13 @@ arch_elf_init(struct ltelf *lte, struct
|
|
|
2e4be5 |
* 400426: 68 00 00 00 00 pushq $0x0
|
|
|
2e4be5 |
* 40042b: e9 e0 ff ff ff jmpq 400410 <_init+0x18>
|
|
|
2e4be5 |
*
|
|
|
2e4be5 |
+ * For CET binaries it is the following:
|
|
|
2e4be5 |
+ *
|
|
|
2e4be5 |
+ * 13d0: f3 0f 1e fa endbr64
|
|
|
2e4be5 |
+ * 13d4: 68 27 00 00 00 pushq $0x27 <-- index
|
|
|
2e4be5 |
+ * 13d9: f2 e9 71 fd ff ff bnd jmpq 1150 <.plt>
|
|
|
2e4be5 |
+ * 13df: 90 nop
|
|
|
2e4be5 |
+ *
|
|
|
2e4be5 |
* On i386, the argument to push is an offset of relocation to
|
|
|
2e4be5 |
* use. The first PLT slot has an offset of 0x0, the second
|
|
|
2e4be5 |
* 0x8, etc. On x86_64, it's directly the index that we are
|
|
|
2e4be5 |
@@ -128,11 +135,33 @@ arch_elf_init(struct ltelf *lte, struct
|
|
|
2e4be5 |
unsigned int i, sz = vect_size(<e->plt_relocs);
|
|
|
2e4be5 |
for (i = 0; i < sz; ++i) {
|
|
|
2e4be5 |
|
|
|
2e4be5 |
- GElf_Addr offset = x86_plt_offset(i);
|
|
|
2e4be5 |
+ GElf_Addr offset = x86_plt_offset(lte, i);
|
|
|
2e4be5 |
+ uint32_t reloc_arg;
|
|
|
2e4be5 |
|
|
|
2e4be5 |
uint8_t byte;
|
|
|
2e4be5 |
- if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|
|
|
2e4be5 |
- || byte != 0xff
|
|
|
2e4be5 |
+ if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0)
|
|
|
2e4be5 |
+ continue;
|
|
|
2e4be5 |
+
|
|
|
2e4be5 |
+
|
|
|
2e4be5 |
+ if (byte == 0xf3
|
|
|
2e4be5 |
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
|
|
|
2e4be5 |
+ && byte == 0x0f
|
|
|
2e4be5 |
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
|
|
|
2e4be5 |
+ && byte == 0x1e
|
|
|
2e4be5 |
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
|
|
|
2e4be5 |
+ && byte == 0xfa
|
|
|
2e4be5 |
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
|
|
|
2e4be5 |
+ && byte == 0x68
|
|
|
2e4be5 |
+ && elf_read_next_u32(lte->plt_data,
|
|
|
2e4be5 |
+ &offset, &reloc_arg) >= 0)
|
|
|
2e4be5 |
+ {
|
|
|
2e4be5 |
+ /* CET */
|
|
|
2e4be5 |
+ fprintf(stderr, "%d: reloc_arg is %lx\n", i, (long)reloc_arg);
|
|
|
2e4be5 |
+ *VECT_ELEMENT(<e->arch.plt_map, unsigned int, reloc_arg) = i;
|
|
|
2e4be5 |
+ continue;
|
|
|
2e4be5 |
+ }
|
|
|
2e4be5 |
+
|
|
|
2e4be5 |
+ if (byte != 0xff
|
|
|
2e4be5 |
|| elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|
|
|
2e4be5 |
|| (byte != 0xa3 && byte != 0x25))
|
|
|
2e4be5 |
continue;
|
|
|
2e4be5 |
@@ -140,7 +169,6 @@ arch_elf_init(struct ltelf *lte, struct
|
|
|
2e4be5 |
/* Skip immediate argument in the instruction. */
|
|
|
2e4be5 |
offset += 4;
|
|
|
2e4be5 |
|
|
|
2e4be5 |
- uint32_t reloc_arg;
|
|
|
2e4be5 |
if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|
|
|
2e4be5 |
|| byte != 0x68
|
|
|
2e4be5 |
|| elf_read_next_u32(lte->plt_data,
|