Implement core dump debugging for PPC64le
ClosedPublic

Authored by alexandreyy on Mon, Nov 6, 4:40 AM.

Details

Summary

Implement core dump debugging for PPC64le.

Diff Detail

Repository
rL LLVM
alexandreyy created this revision.Mon, Nov 6, 4:40 AM
labath added a subscriber: labath.Mon, Nov 6, 5:58 AM

We were quite successful in the past in creating tiny core files to test these register contexts. Could you take a look at test/testcases/functionalities/postmortem/elf-core/make-core.sh to see if you can do the same for your architecture?

source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.h
23 ↗(On Diff #121719)

delete this ?

source/Plugins/Process/elf-core/ThreadElfCore.h
183 ↗(On Diff #121719)

gpregset and fpregset sound fairly generic, but these other two sound really architecture specific. Since ThreadElfCore does not really do anything with these, just pass them to the register context, I'm thinking that we could just have a map of all register sets (something like DenseMap<uint32_t, DataExtractor>). Then we can just pass that to the register context constructor, and let it figure out what to do with it. What do you think?

clayborg added inline comments.
source/Plugins/Process/elf-core/ThreadElfCore.h
183 ↗(On Diff #121719)

That sounds like a good idea to me.

Update according to reviews.

alexandreyy added a comment.EditedThu, Nov 9, 4:25 AM

Thanks for all the reviews @labath and @clayborg.
I changed the code to use the DenseMap and added the files for testing.
The backtrace is not working properly yet,
It is not showing all frames, just the current.
Am I missing something?

labath added a comment.Thu, Nov 9, 5:06 AM

I'm not sure what's the problem with backtracing without more info, but the nice thing about core files is that you can open a ppc and x86 one side by side and see how for do you get before things start to diverge. The interesting commands you can start with are "image lookup" (to see if you can find symbols properly), "image show-unwind" (to see the unwind plans) and "log enable lldb unwind && bt" (to see backtracing in action). This is what I get for the x86_64 core file (you should be able to see the same thing yourself):

(lldb) bt
* thread #1, name = 'a.out', stop reason = signal SIGSEGV
  * frame #0: 0x000000000040011c linux-x86_64.out`bar(boom=0x0000000000000000) at main.c:4
    frame #1: 0x0000000000400142 linux-x86_64.out`foo(boom=0x0000000000000000, boomer=(linux-x86_64.out`bar at main.c:2)) at main.c:10
    frame #2: 0x000000000040015f linux-x86_64.out`_start at main.c:16
(lldb) image lookup -n bar
1 match found in /usr/local/google/home/labath/ll/lldb/test/testcases/functionalities/postmortem/elf-core/linux-x86_64.out:
        Address: linux-x86_64.out[0x000000000040010c] (linux-x86_64.out..text + 0)
        Summary: linux-x86_64.out`bar at main.c:2
(lldb) image show-unwind -n bar
UNWIND PLANS for linux-x86_64.out`bar (start addr 0x40010c)

Asynchronous (not restricted to call-sites) UnwindPlan is 'assembly insn profiling'
Synchronous (restricted to call-sites) UnwindPlan is 'eh_frame CFI'
Fast UnwindPlan is 'x86_64 default unwind plan'

Assembly language inspection UnwindPlan:
This UnwindPlan originally sourced from assembly insn profiling
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: yes.
Address range of this UnwindPlan: [linux-x86_64.out..text + 0-0x0000000000000015)
row[0]:    0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 
row[1]:    1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 
row[2]:    4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 
row[3]:   20: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 

eh_frame UnwindPlan:
This UnwindPlan originally sourced from eh_frame CFI
This UnwindPlan is sourced from the compiler: yes.
This UnwindPlan is valid at all instruction locations: no.
Address range of this UnwindPlan: [linux-x86_64.out..text + 0-0x0000000000000015)
row[0]:    0: CFA=rsp +8 => rip=[CFA-8] 
row[1]:    1: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8] 
row[2]:    4: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8] 
row[3]:   20: CFA=rsp +8 => rbp=[CFA-16] rip=[CFA-8] 

Fast UnwindPlan:
This UnwindPlan originally sourced from x86_64 default unwind plan
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: no.
row[0]:    0: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 

Arch default UnwindPlan:
This UnwindPlan originally sourced from x86_64 default unwind plan
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: no.
row[0]:    0: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 

Arch default at entry point UnwindPlan:
This UnwindPlan originally sourced from x86_64 at-func-entry default
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: not specified.
row[0]:    0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
source/Plugins/Process/elf-core/ProcessElfCore.cpp
659 ↗(On Diff #122224)

I don't think we should make up new constants for the map indices, when we already have the NT_*** constants. You just need to move the constants to a header, so that you can use them from other files. The general purpose registers are the only ones that don't have a special constant, but we can probably agree to use NT_PRSTATUS for this, as that's where we're plucking them from anyway.

718 ↗(On Diff #122224)

The good thing about these maps is that you don't have to check for the architecture here. You can just store this unconditionally there, and leave it up to the consumer to decide if he wants to make use of it.

source/Plugins/Process/elf-core/RegisterContextPOSIXCore_ppc64le.h
26 ↗(On Diff #122224)

The DenseMap isn't exactly cheap to copy. You should probably pass a (constant) reference here.

alexandreyy marked an inline comment as done.

Moved core enums to header file.

I'm not sure what's the problem with backtracing without more info, but the nice thing about core files is that you can open a ppc and x86 one side by side and see how for do you get before things start to diverge. The interesting commands you can start with are "image lookup" (to see if you can find symbols properly), "image show-unwind" (to see the unwind plans) and "log enable lldb unwind && bt" (to see backtracing in action). This is what I get for the x86_64 core file (you should be able to see the same thing yourself):

(lldb) bt
* thread #1, name = 'a.out', stop reason = signal SIGSEGV
  * frame #0: 0x000000000040011c linux-x86_64.out`bar(boom=0x0000000000000000) at main.c:4
    frame #1: 0x0000000000400142 linux-x86_64.out`foo(boom=0x0000000000000000, boomer=(linux-x86_64.out`bar at main.c:2)) at main.c:10
    frame #2: 0x000000000040015f linux-x86_64.out`_start at main.c:16
(lldb) image lookup -n bar
1 match found in /usr/local/google/home/labath/ll/lldb/test/testcases/functionalities/postmortem/elf-core/linux-x86_64.out:
        Address: linux-x86_64.out[0x000000000040010c] (linux-x86_64.out..text + 0)
        Summary: linux-x86_64.out`bar at main.c:2
(lldb) image show-unwind -n bar
UNWIND PLANS for linux-x86_64.out`bar (start addr 0x40010c)

Asynchronous (not restricted to call-sites) UnwindPlan is 'assembly insn profiling'
Synchronous (restricted to call-sites) UnwindPlan is 'eh_frame CFI'
Fast UnwindPlan is 'x86_64 default unwind plan'

Assembly language inspection UnwindPlan:
This UnwindPlan originally sourced from assembly insn profiling
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: yes.
Address range of this UnwindPlan: [linux-x86_64.out..text + 0-0x0000000000000015)
row[0]:    0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 
row[1]:    1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 
row[2]:    4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 
row[3]:   20: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 

eh_frame UnwindPlan:
This UnwindPlan originally sourced from eh_frame CFI
This UnwindPlan is sourced from the compiler: yes.
This UnwindPlan is valid at all instruction locations: no.
Address range of this UnwindPlan: [linux-x86_64.out..text + 0-0x0000000000000015)
row[0]:    0: CFA=rsp +8 => rip=[CFA-8] 
row[1]:    1: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8] 
row[2]:    4: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8] 
row[3]:   20: CFA=rsp +8 => rbp=[CFA-16] rip=[CFA-8] 

Fast UnwindPlan:
This UnwindPlan originally sourced from x86_64 default unwind plan
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: no.
row[0]:    0: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 

Arch default UnwindPlan:
This UnwindPlan originally sourced from x86_64 default unwind plan
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: no.
row[0]:    0: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 

Arch default at entry point UnwindPlan:
This UnwindPlan originally sourced from x86_64 at-func-entry default
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: not specified.
row[0]:    0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]

Thanks. I moved the enums and I will investigate that problem using these commands.

labath added a comment.Thu, Nov 9, 7:42 AM

Thank you. I've just noticed a couple of details we should address.

source/Plugins/Process/elf-core/elf-core-enums.h
1 ↗(On Diff #122239)

Please update the file name here and add header guards.

11 ↗(On Diff #122239)

I'm sorry for the back and forth, but since we're already moving these, I think we should also put these into a linux namespace, as these are really linux-specific constants (except the NT_OPENBSD_*** ones, which should obviously get a namespace of their own (namespace OPENBSD { enum {NT_PROCINFO = ...}; })).

Changed namespaces in core enums.

Fixed test identation

labath accepted this revision.Fri, Nov 10, 2:55 AM

Looks good, thank you. Just please make sure you change the file name at top of the new header file and add inclusion guards.

source/Plugins/Process/elf-core/elf-core-enums.h
1 ↗(On Diff #122239)

I think you've missed this one.

This revision is now accepted and ready to land.Fri, Nov 10, 2:55 AM

Added inclusion guards in elf-core-enums.h

Looks good, thank you. Just please make sure you change the file name at top of the new header file and add inclusion guards.

Done. Could you commit it?
I don't have commit access.

Fixed backtrace issue.

I'm not sure what's the problem with backtracing without more info, but the nice thing about core files is that you can open a ppc and x86 one side by side and see how for do you get before things start to diverge. The interesting commands you can start with are "image lookup" (to see if you can find symbols properly), "image show-unwind" (to see the unwind plans) and "log enable lldb unwind && bt" (to see backtracing in action). This is what I get for the x86_64 core file (you should be able to see the same thing yourself):

(lldb) bt
* thread #1, name = 'a.out', stop reason = signal SIGSEGV
  * frame #0: 0x000000000040011c linux-x86_64.out`bar(boom=0x0000000000000000) at main.c:4
    frame #1: 0x0000000000400142 linux-x86_64.out`foo(boom=0x0000000000000000, boomer=(linux-x86_64.out`bar at main.c:2)) at main.c:10
    frame #2: 0x000000000040015f linux-x86_64.out`_start at main.c:16
(lldb) image lookup -n bar
1 match found in /usr/local/google/home/labath/ll/lldb/test/testcases/functionalities/postmortem/elf-core/linux-x86_64.out:
        Address: linux-x86_64.out[0x000000000040010c] (linux-x86_64.out..text + 0)
        Summary: linux-x86_64.out`bar at main.c:2
(lldb) image show-unwind -n bar
UNWIND PLANS for linux-x86_64.out`bar (start addr 0x40010c)

Asynchronous (not restricted to call-sites) UnwindPlan is 'assembly insn profiling'
Synchronous (restricted to call-sites) UnwindPlan is 'eh_frame CFI'
Fast UnwindPlan is 'x86_64 default unwind plan'

Assembly language inspection UnwindPlan:
This UnwindPlan originally sourced from assembly insn profiling
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: yes.
Address range of this UnwindPlan: [linux-x86_64.out..text + 0-0x0000000000000015)
row[0]:    0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 
row[1]:    1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 
row[2]:    4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 
row[3]:   20: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 

eh_frame UnwindPlan:
This UnwindPlan originally sourced from eh_frame CFI
This UnwindPlan is sourced from the compiler: yes.
This UnwindPlan is valid at all instruction locations: no.
Address range of this UnwindPlan: [linux-x86_64.out..text + 0-0x0000000000000015)
row[0]:    0: CFA=rsp +8 => rip=[CFA-8] 
row[1]:    1: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8] 
row[2]:    4: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8] 
row[3]:   20: CFA=rsp +8 => rbp=[CFA-16] rip=[CFA-8] 

Fast UnwindPlan:
This UnwindPlan originally sourced from x86_64 default unwind plan
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: no.
row[0]:    0: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 

Arch default UnwindPlan:
This UnwindPlan originally sourced from x86_64 default unwind plan
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: no.
row[0]:    0: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 

Arch default at entry point UnwindPlan:
This UnwindPlan originally sourced from x86_64 at-func-entry default
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: not specified.
row[0]:    0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]

I have fixed the backtrace issue.
The lr register was in a wrong position in RegisterInfos_ppc64le.h ,
Could you, please, submit these changes, @labath ?
Thanks! ;)

Removed issue note from commit message.

krytarowski added inline comments.
source/Plugins/Process/elf-core/elf-core-enums.h
14 ↗(On Diff #122879)

No namespace here?

alexandreyy added inline comments.Tue, Nov 14, 11:44 AM
source/Plugins/Process/elf-core/elf-core-enums.h
14 ↗(On Diff #122879)

I think these constants are used for multiple OSs.
Am I correct?
Do you have a suggestion for a namespace?

krytarowski added inline comments.Tue, Nov 14, 11:52 AM
source/Plugins/Process/elf-core/elf-core-enums.h
14 ↗(On Diff #122879)

There is rumor that they came from SVR4.. but I don't have the specs to make sure.

Multiple in this case does not mean "all". This is not true for at least NetBSD.

alexandreyy added inline comments.Tue, Nov 14, 12:12 PM
source/Plugins/Process/elf-core/elf-core-enums.h
14 ↗(On Diff #122879)

I can remove these constants and modify the first "if" in ParseThreadContextsFromNoteSegment to:

if (((note.n_type == LINUX::NT_PRSTATUS ||
        note.n_type == FREEBSD::NT_PRSTATUS) && have_prstatus) ||
      ((note.n_type == LINUX::NT_PRPSINFO ||
        note.n_type == FREEBSD::NT_PRPSINFO) && have_prpsinfo)) {
    assert(thread_data->gpregset.GetByteSize() > 0);

What do you think?
But NT_PRSTATUS and NT_PRPSINFO have the same value for Linux and FreeBSD .

krytarowski added inline comments.Tue, Nov 14, 12:30 PM
source/Plugins/Process/elf-core/elf-core-enums.h
14 ↗(On Diff #122879)

I propose to put NT_PRSTATUS, NT_PRFPREG, NT_PRPSINFO into this namespace and call it SVR4.

SmartOS uses the same values.

labath added inline comments.Wed, Nov 15, 1:53 AM
source/Plugins/Process/elf-core/elf-core-enums.h
14 ↗(On Diff #122879)

With the addition of all the bsd variants, the note parsing code has grown pretty big.

My plan was to refactor it a bit after this is committed. I wanted to split it into two stages: first we just determine the OS from the notes; and then we dispatch to an appropriate os-specific function to do the actual parsing (with each function just using the NT constants from its own namespace). If you agree with that direction then I propose to go with the LINUX::NT_PRSTATUS || FREEBSD::NT_PRSTATUS proposed by alexandreyy in the interim.

Also, I have trouble downloading the core file from phabricator. Alexandre, can you sent them to me directly?

krytarowski added inline comments.Wed, Nov 15, 2:59 AM
source/Plugins/Process/elf-core/elf-core-enums.h
14 ↗(On Diff #122879)

Sounds good.

Removed enums without namespaces.

Also, I have trouble downloading the core file from phabricator. Alexandre, can you sent them to me directly?

Sent the test files by e-mail.
Thanks.

This revision was automatically updated to reflect the committed changes.
bsdjhb added a subscriber: bsdjhb.Thu, Nov 16, 9:46 AM
bsdjhb added inline comments.
source/Plugins/Process/elf-core/elf-core-enums.h
14 ↗(On Diff #122879)

Yes, that is probably the right approach. In binutils the note parsing code switches on the note name ("FreeBSD" vs "NetBSD" vs "CORE" vs "Linux", etc.) and then inside name-specific functions switches on the note type. I've been adding support for more notes to GDB for FreeBSD and ended up splitting out a handler for "FreeBSD" notes inline with this approach. Even notes with the same type (NT_PRSTATUS, etc.) have different layouts across OS's.