This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Fix reading of PC values of FDEs
ClosedPublic

Authored by atanasyan on Feb 29 2016, 1:45 PM.

Details

Summary

The patch fixes two related problems:

  • If CIE augmentation string has 'L' token the CIE contains a byte defines LSDA encoding. We should skip this byte in getFdeEncoding routine. Before this fix we do not skip it and if the next token is 'R' treat this byte as FDE encoding.
  • FDE encoding format has separate flags e.g. DW_EH_PE_pcrel for definition of relative pointers. We should add .eh_frame address to the PC value iif the DW_EH_PE_pcrel is specified.

http://www.airs.com/blog/archives/460

There is one more not fixed problem in this code. If PC value is encoded using signed relative format e.g. DW_EH_PE_sdata4 | DW_EH_PE_pcrel we should sign extend result of read32 to perform calculation correctly. I am going to fix that in a separate patch.

Diff Detail

Repository
rL LLVM

Event Timeline

atanasyan updated this revision to Diff 49411.Feb 29 2016, 1:45 PM
atanasyan retitled this revision from to [ELF] Fix reading of PC values of FDEs.
atanasyan updated this object.
atanasyan added reviewers: ruiu, rafael.
atanasyan set the repository for this revision to rL LLVM.
atanasyan added a project: lld.
atanasyan added a subscriber: llvm-commits.
rafael added inline comments.Feb 29 2016, 2:32 PM
ELF/OutputSections.cpp
675 ↗(On Diff #49411)

This might be shorter as a lambda so that you can just return PC.

test/ELF/eh-frame-hdr-abs-fde.s
21 ↗(On Diff #49411)

Can you use objdump to get a parsed content?

atanasyan added inline comments.Feb 29 2016, 11:35 PM
ELF/OutputSections.cpp
675 ↗(On Diff #49411)

Do you mean something like that?

auto Adjust = [=](uint64_t PC) {
  return IsRelative ? PC + EhVA + F.Off + 8 : PC;
};
...
case DW_EH_PE_sdata4:
  return Adjust(read32<E>(F.PCRel));
test/ELF/eh-frame-hdr-abs-fde.s
21 ↗(On Diff #49411)

It looks like I need to fix the llvm-objdump first. Now it shows Augmentation data as a regular string but it might contain non-printable characters. GNU objdump shows it as hex numbers.

grimar edited subscribers, added: grimar; removed: georgerim.Mar 1 2016, 1:53 AM
atanasyan updated this revision to Diff 49537.Mar 1 2016, 1:05 PM
  • Reduce size of code using lambda function
  • Use llvm-objdump -dwarf=frames to make checking in the test more clear
rafael accepted this revision.Mar 1 2016, 1:10 PM
rafael edited edge metadata.

LGTM

This revision is now accepted and ready to land.Mar 1 2016, 1:10 PM
ruiu added inline comments.Mar 1 2016, 1:19 PM
ELF/OutputSections.cpp
669–670 ↗(On Diff #49537)

Do you have to use lambda? It seems you can write without it in a more regular way.

const endianness E = ELFT::TargetEndianness;

int Size = F.Enc & 0x7;
if (Size == DW_EH_PE_absptr)
  Size = sizeof(uintX_t) == 8 ? DW_EH_PE_udata8 : DW_EH_PE_udata4;

uintX_t V;
switch (Size) {
case DW_EH_PE_udata2:
  V = read16<E>(F.PCRel);
case DW_EH_PE_udata4:
  V = read32<E>(F.PCRel);
case DW_EH_PE_udata8:
  V = read64<E>(F.PCRel);
default:
  fatal("unknown FDE size encoding");
}

switch (F.Enc & 0x70) {
case DW_EH_PE_absptr:
  return V;
case DW_EH_PE_pcrel:
  return V + EhVA + F.Off + 8;
default:
  fatal("unknown FDE size relative encoding");
}
atanasyan added inline comments.Mar 1 2016, 1:30 PM
ELF/OutputSections.cpp
669–670 ↗(On Diff #49537)

Do you have to use lambda? It seems you can write without it in a more regular way.

The lambda is not mandatory. But without it the code is a bit longer because we have to add break to each case of the switch (Size).

Small preference for a lambda, but LGTM without it too if Rui prefers
it that way.

Cheers,
Rafael

This revision was automatically updated to reflect the committed changes.

Thanks for review. I have committed the code without lambda function.