Skip to content
Snippets Groups Projects
Commit 846ed4ca authored by Jonas Rabenstein's avatar Jonas Rabenstein
Browse files

WIP: objtool: orc: support for groups

parent 75e9a9e6
Branches objtool
No related tags found
No related merge requests found
...@@ -140,6 +140,23 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti ...@@ -140,6 +140,23 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti
return 0; return 0;
} }
static unsigned orc_entry_count(struct objtool_file *file, struct section *sec)
{
struct instruction *insn, *prev;
unsigned count = 0;
prev = NULL;
sec_for_each_insn(file, sec, insn) {
if (!prev || memcmp(&insn->orc, &prev->orc,
sizeof(struct orc_entry)))
count++;
prev = insn;
}
if (prev)
count++;
return count;
}
int create_orc_sections(struct objtool_file *file) int create_orc_sections(struct objtool_file *file)
{ {
struct instruction *insn, *prev_insn; struct instruction *insn, *prev_insn;
...@@ -163,24 +180,10 @@ int create_orc_sections(struct objtool_file *file) ...@@ -163,24 +180,10 @@ int create_orc_sections(struct objtool_file *file)
for_each_sec(file, sec) { for_each_sec(file, sec) {
if (!sec->text) if (!sec->text)
continue; continue;
if (sec->sh.sh_flags & SHF_GROUP)
prev_insn = NULL; continue;
sec_for_each_insn(file, sec, insn) { idx += orc_entry_count(file, sec);
if (!prev_insn ||
memcmp(&insn->orc, &prev_insn->orc,
sizeof(struct orc_entry))) {
idx++;
}
prev_insn = insn;
}
/* section terminator */
if (prev_insn)
idx++;
} }
if (!idx)
return -1;
/* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), idx); sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), idx);
...@@ -198,34 +201,103 @@ int create_orc_sections(struct objtool_file *file) ...@@ -198,34 +201,103 @@ int create_orc_sections(struct objtool_file *file)
/* populate sections */ /* populate sections */
idx = 0; idx = 0;
for_each_sec(file, sec) { for_each_sec(file, sec) {
struct section *reloc;
struct section *unwind;
unsigned counter;
if (!sec->text) if (!sec->text)
continue; continue;
if (sec->sh.sh_flags & SHF_GROUP) {
struct section *i_sec, *group;
char name[strlen(".orc_unwind_ip") + strlen(sec->name) + 1];
counter = orc_entry_count(file, sec);
if (counter == 0)
continue;
snprintf(name, sizeof(name), ".orc_unwind_ip%s", sec->name);
/* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
i_sec = elf_create_section(file->elf, name, SHF_GROUP, sizeof(int), counter);
if (!i_sec)
return -1;
reloc = elf_create_reloc_section(file->elf, i_sec, SHT_RELA);
if (!reloc)
return -1;
/* create .orc_unwind section */
snprintf(name, sizeof(name), ".orc_unwind%s", sec->name);
unwind= elf_create_section(file->elf, name, SHF_GROUP,
sizeof(struct orc_entry), counter);
/* add to groups */
for_each_sec(file, group) {
bool relevant = false;
unsigned i;
Elf32_Word *member;
if (group->sh.sh_type != SHT_GROUP)
continue;
member = group->data->d_buf;
for (i = 1; !relevant && i < group->len / sizeof(*member); ++i)
if (sec->idx == member[i])
relevant = true;
if (!relevant)
continue;
WARN("group: %s len:%u size:%zu", group->name,
group->len, group->data->d_size);
member = malloc(group->len + (sizeof(*member) * 3));
if (!member)
return -1;
memcpy(member, group->data->d_buf, group->len);
member[group->len/sizeof(*member) + 0] = unwind->idx;
member[group->len/sizeof(*member) + 1] = i_sec->idx;
member[group->len/sizeof(*member) + 2] = reloc->idx;
group->data->d_buf = member;
group->data->d_size = group->len + (3 * sizeof(*member));
group->len = group->len + (3 * sizeof(*member));
group->changed = true;
}
counter = 0;
} else {
unwind = u_sec;
reloc = ip_relocsec;
counter = idx;
}
WARN("create orc in %s", unwind->name);
prev_insn = NULL; prev_insn = NULL;
sec_for_each_insn(file, sec, insn) { sec_for_each_insn(file, sec, insn) {
if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc, if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc,
sizeof(struct orc_entry))) { sizeof(struct orc_entry))) {
if (create_orc_entry(file->elf, u_sec, ip_relocsec, idx, if (create_orc_entry(file->elf, unwind, reloc,
insn->sec, insn->offset, counter, insn->sec,
&insn->orc)) insn->offset, &insn->orc))
return -1; return -1;
idx++; counter++;
} }
prev_insn = insn; prev_insn = insn;
} }
/* section terminator */ /* section terminator */
if (prev_insn) { if (prev_insn) {
if (create_orc_entry(file->elf, u_sec, ip_relocsec, idx, if (create_orc_entry(file->elf, unwind, reloc, counter,
prev_insn->sec, prev_insn->sec,
prev_insn->offset + prev_insn->len, prev_insn->offset + prev_insn->len,
&empty)) &empty))
return -1; return -1;
idx++; counter++;
} }
if (!(sec->sh.sh_flags & SHF_GROUP))
idx = counter;
else if (elf_rebuild_reloc_section(file->elf, reloc))
return -1;
} }
if (elf_rebuild_reloc_section(file->elf, ip_relocsec)) if (elf_rebuild_reloc_section(file->elf, ip_relocsec))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment