Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Backtrace Screen #1270

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Add Backtrace Screen #1270

wants to merge 6 commits into from

Conversation

MrCirdo
Copy link
Contributor

@MrCirdo MrCirdo commented Jul 19, 2023

Hello everyone!

This is my first big pull request 😃

The goal of this PR is to add a backtrace screen for process or thread.
Here's what it looks like for a thread :
image

And for a process:
image

Behind, I use the tool called eu-stack provided by elf-utils.
The standard output is parsed and printed to the screen.
Currently, I have implemented only the Refresh button. And my world is inspired by TraceScreen and OpenFilesScreen.

I still have some work to do before my work is ready (Formatting, bug fixes, ...).
Currently, this is more of a demonstration than a cool feature 😄 .

What do you think about my work? Is it a feature that can be added?

@BenBE BenBE added the new feature Completely new feature label Jul 19, 2023
Copy link
Member

@BenBE BenBE left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for your PR. The feature itself looks interesting and fits quite nicely with existing functionality.

But, the use of external tools is a bit problematic and is best to be avoided. For the case of retrieving stack traces, there are several libraries available, that might be worth a look (e.g. libunwind). Also I'm not sure if the code as-is would properly run on e.g. FreeBSD or Darwin. Thus I strongly prefer a solution that allows to split out these platform-dependent parts where necessary (in the case of lsof, things are portable enough across all our target platforms so it's not an issue there; not sure about eu-stack though).

While reading through your PR I noticed that this seems to handle debug information. As such, it would be nice to have the module, source file and line be available separately (where available). Also the setting of hiding path names should be respected for module filenames in order to be consistent with the rest of the UI. Taking the highlight basename setting into account would be nice too.

Another code refactoring task is related to a recent addition of the generalized columns code that @natoscott recently worked on. Please have a look there if you like.

Also there's a few further notes regarding the code which you can find below. Please feel free to rebase the fixes to those issues directly into the existing commits as you see fit.

If you need further assistance feel free to ask.

Action.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.h Outdated Show resolved Hide resolved
BacktraceScreen.h Outdated Show resolved Hide resolved
BacktraceScreen.h Outdated Show resolved Hide resolved
BacktraceScreen.h Show resolved Hide resolved
@MrCirdo
Copy link
Contributor Author

MrCirdo commented Jul 20, 2023

Thank you for your reactivity and your review.

I agree with you when you say eu-stack is not a good idea. I only used it to make a quick demo of my idea.
I'm also unsure if eu-stack is supported on the BSD platforms.

Moreover, I think also the library unwind is more appropriate. I just have to deal with DWARF information.
I will probably close all suggestions regarding the execution/parsing of eu-stack.

I saw very quickly the work of @natoscott and I will wait until his work is finished.

BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
@BenBE
Copy link
Member

BenBE commented Jul 20, 2023

Thank you for your reactivity and your review.

You're welcome.

I agree with you when you say eu-stack is not a good idea. I only used it to make a quick demo of my idea. I'm also unsure if eu-stack is supported on the BSD platforms.

There seems to be some patches re FreeBSD, but I'd not actually call this support … ;-)

That's with Darwin aside entirely … ;-)

Moreover, I think also the library unwind is more appropriate. I just have to deal with DWARF information. I will probably close all suggestions regarding the execution/parsing of eu-stack.

Sure, go ahead. Maybe check for similar places elsewhere in case something similar was missed in other places of this PR.

I saw very quickly the work of @natoscott and I will wait until his work is finished.

If you prepare your PR to anticipate that change, e.g. by preparing the data structures in a way that makes this move easy, you could even prepare things now. Given the remaining aspects in that other PR will take some time to sort out, don't feel obliged to wait for those changes to land. If the structures introduced in this PR are clean enough there's not too much work later to move things over to this new interface. Most of the work actually has already been done.

@Explorer09
Copy link
Contributor

Please don't merge the htop-dev:main branch. Rebase it instead. You know what git rebase is, don't you?

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Sep 5, 2023

The flake commit is just for me. I will remove it at the end.
I don't start my work. However, I keep updating my branch. So it's not ready to review.

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Nov 16, 2023

Hey,

I didn't have a lot of time recently for this PR. But I have some questions.

If you prepare your PR to anticipate that change, e.g. by preparing the data structures in a way that makes this move easy, you could even prepare things now. Given the remaining aspects in that other PR will take some time to sort out, don't feel obliged to wait for those changes to land. If the structures introduced in this PR are clean enough there's not too much work later to move things over to this new interface. Most of the work actually has already been done.

I'm looking for Row workflow. I don't know if it's a good idea to use it. Row_display uses the object Settings to get fields. Does it mean I have to make my own Settings object? With all process settings (like highlightThreads)? And do I have to make my ScreenSettings? Is it okay?

@BenBE
Copy link
Member

BenBE commented Nov 16, 2023

I didn't have a lot of time recently for this PR. But I have some questions.

If you prepare your PR to anticipate that change, e.g. by preparing the data structures in a way that makes this move easy, you could even prepare things now. Given the remaining aspects in that other PR will take some time to sort out, don't feel obliged to wait for those changes to land. If the structures introduced in this PR are clean enough there's not too much work later to move things over to this new interface. Most of the work actually has already been done.

I'm looking for Row workflow. I don't know if it's a good idea to use it. Row_display uses the object Settings to get fields. Does it mean I have to make my own Settings object? With all process settings (like highlightThreads)? And do I have to make my ScreenSettings? Is it okay?

The Settings and ScreenSettings objects are shared between all tabs. The Settings provides with the global settings, applicable to all screens, while ScreenSettings is applicable to only to the current tab only. As you are basically inheriting the settings from the tab you are opening the backtrace details on, you can just copy the pointer to those settings. These are held in the Screen mostly for convenience and to reduce dependency scope. I.e. if you don't need any of the values from the settings (and none of the functions you're relying on) you could even skip these objects entirely.

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Nov 17, 2023

I didn't have a lot of time recently for this PR. But I have some questions.

If you prepare your PR to anticipate that change, e.g. by preparing the data structures in a way that makes this move easy, you could even prepare things now. Given the remaining aspects in that other PR will take some time to sort out, don't feel obliged to wait for those changes to land. If the structures introduced in this PR are clean enough there's not too much work later to move things over to this new interface. Most of the work actually has already been done.

I'm looking for Row workflow. I don't know if it's a good idea to use it. Row_display uses the object Settings to get fields. Does it mean I have to make my own Settings object? With all process settings (like highlightThreads)? And do I have to make my ScreenSettings? Is it okay?

The Settings and ScreenSettings objects are shared between all tabs. The Settings provides with the global settings, applicable to all screens, while ScreenSettings is applicable to only to the current tab only. As you are basically inheriting the settings from the tab you are opening the backtrace details on, you can just copy the pointer to those settings. These are held in the Screen mostly for convenience and to reduce dependency scope. I.e. if you don't need any of the values from the settings (and none of the functions you're relying on) you could even skip these objects entirely.

Thank you very much for the clarification. I was not sure I would be able to modify it (I mean If my changes would be accepted).

Copy link
Member

@BenBE BenBE left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please no custom build system files from e.g. Flake …

BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Show resolved Hide resolved
BacktraceScreen.c Show resolved Hide resolved
BacktraceScreen.h Show resolved Hide resolved
@MrCirdo
Copy link
Contributor Author

MrCirdo commented Jan 9, 2024

Hi @BenBE ,
I completely forgot to say to not review my code. I just updated my branch.
I deeply apologize.

@BenBE
Copy link
Member

BenBE commented Jan 9, 2024

Hi @BenBE , I completely forgot to say to not review my code. I just updated my branch. I deeply apologize.

Don't worry. No need to apologize. The PR is marked as draft anyway, thus the only things I remarked upon was what I noticed immediately. I also ticked off some of the previous comments that no longer apply to the current state of this PR. Basically some maintenance.

NB: This PR would be scheduled for 3.4.x earliest anyway given that 3.3.0 is about to ship anytime soon.

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Mar 16, 2024

Hi,

This PR is ready for review.
I closed all previous conversations.

Currently, I add only the support of Linux.

@MrCirdo MrCirdo marked this pull request as ready for review March 16, 2024 17:35
configure.ac Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
@MrCirdo MrCirdo force-pushed the main branch 2 times, most recently from c53af06 to 792bdba Compare March 16, 2024 20:46
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.c Outdated Show resolved Hide resolved
BacktraceScreen.h Outdated Show resolved Hide resolved
configure.ac Outdated Show resolved Hide resolved
@BenBE
Copy link
Member

BenBE commented Mar 17, 2024

Given that this feature will be available on multiple platforms and requires changes in different places I'd suggest to have a top-level feature flag for backtrace support and additional flags for the various libraries (iberty, eu-stack, …) The actual implementation for the stack traces should go in the platform code for each system, leaving the actual screen implementation mostly platform independent.

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Mar 19, 2024

Given that this feature will be available on multiple platforms and requires changes in different places I'd suggest to have a top-level feature flag for backtrace support and additional flags for the various libraries (iberty, eu-stack, …) The actual implementation for the stack traces should go in the platform code for each system, leaving the actual screen implementation mostly platform independent.

Ok I see what you mean, is it a good idea to be inspired by for example Machine_new?

@BenBE
Copy link
Member

BenBE commented Mar 19, 2024

Given that this feature will be available on multiple platforms and requires changes in different places I'd suggest to have a top-level feature flag for backtrace support and additional flags for the various libraries (iberty, eu-stack, …) The actual implementation for the stack traces should go in the platform code for each system, leaving the actual screen implementation mostly platform independent.

Ok I see what you mean, is it a good idea to be inspired by for example Machine_new?

Maybe a better candidate may be the way in which Platform_getNetworkIO and Platform_getProcessLocks are implemented in <platform>/*Platform.[ch]

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Mar 20, 2024

Given that this feature will be available on multiple platforms and requires changes in different places I'd suggest to have a top-level feature flag for backtrace support and additional flags for the various libraries (iberty, eu-stack, …) The actual implementation for the stack traces should go in the platform code for each system, leaving the actual screen implementation mostly platform independent.

Ok I see what you mean, is it a good idea to be inspired by for example Machine_new?

Maybe a better candidate may be the way in which Platform_getNetworkIO and Platform_getProcessLocks are implemented in <platform>/*Platform.[ch]

Okay thank you, I'll take a look

@MrCirdo MrCirdo force-pushed the main branch 4 times, most recently from 053df6c to a1344de Compare November 14, 2024 21:08
@MrCirdo
Copy link
Contributor Author

MrCirdo commented Nov 25, 2024

Normally, I should have corrected all the comments.

linux/Platform.c Outdated Show resolved Hide resolved
Action.c Show resolved Hide resolved
linux/Platform.c Outdated Show resolved Hide resolved
@MrCirdo
Copy link
Contributor Author

MrCirdo commented Nov 26, 2024

I'm wondering about the future of this pull request. Is there any chance of it being merged? Or are other adjustments needed (which will be welcome).

@BenBE
Copy link
Member

BenBE commented Nov 26, 2024

What I've seen so far looks good, with probably a few minor adjustments still needed (haven't had time for a deep review yet).

Also, I kinda already hinted on future features that would be nice to have (file/line info for code locations), but these can go into a future PR.. Also adding support for other supported platforms is something that can be added after initial support has landed.

What might be worth looking into before merging this, if these changes can be easily accommodated with the following PR (AFAICS they should), but it doesn't hurt to have a second pair of eyes looking into this too.

TL;DR: PR looks good and chances are good it will be merged. Just no ETA yet due to other workload (apart from htop).

static int BacktraceFrame_compare(const void* object1, const void* object2) {
const BacktraceFrame* frame1 = (const BacktraceFrame*)object1;
const BacktraceFrame* frame2 = (const BacktraceFrame*)object2;
return String_eq(frame1->functionName, frame2->functionName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return String_eq(frame1->functionName, frame2->functionName);
return SPACESHIP_NULLSTR(frame1->functionName, frame2->functionName);

Copy link
Contributor Author

@MrCirdo MrCirdo Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good catch. I just learned when a NULL pointer is passed to strcmp, it's an undefined behavior.


for (int i = 0; i < Vector_size(lines); i++) {
BacktraceFrame* frame = (BacktraceFrame*)Vector_get(lines, i);
frame->backtracePanel = this;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this line do in particular? An issue I just found out is this break the const assumption of the BacktracePanel* this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BacktracePanel contains all BacktraceFrame instances, making frames easily accessible via the items attribute. However, accessing the panel from a frame is more complex. To address this, I added a weak reference from each frame to the panel, allowing panel access (e.g., for settings) when only a frame object is available. It is const because it ensures the panel isn’t modified or freed (without a cast).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure where you need the BacktracePanel reference from the BacktraceFrame, but the makePrintingHelper function is supposed to do one thing - the preparation of the "printing helper" data. It's not supposed to modify the BacktraceFrame objects.

If you do need the references from the frame, I suggest you set the references when the frame objects are allocated. This might require you to modify the BacktraceFrame_new() function to take one parameter, for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes It's true, it's a good observation. Introducing void BacktraceFrame_new(Panel *panel) says clearly that is a weak dependency, but it also means that I need to pass a Panel * to Platform_getBacktrace.

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Nov 27, 2024

PR looks good and chances are good it will be merged.

It's great news!

Just no ETA yet due to other workload (apart from htop)

Yes, no problem 😄

Also, I kinda already hinted on future features that would be nice to have (file/line info for code locations), but these can go into a future PR.. Also adding support for other supported platforms is something that can be added after initial support has landed.

I prefer to separate them into multiple PRs. For other platforms, I don't know well BSD (OpenBSD, FreeBSD, etc.) and I don't have a Mac (and my GPU is not compatible with macOS)... For more information like code location, a change is needed into libunwind or a new backend is required.

What might be worth looking into before merging this, if these changes can be easily accommodated with the following PR (AFAICS they should), but it doesn't hurt to have a second pair of eyes looking into this too

Which PR do you mean?

@BenBE
Copy link
Member

BenBE commented Nov 27, 2024

What might be worth looking into before merging this, if these changes can be easily accommodated with the following PR (AFAICS they should), but it doesn't hurt to have a second pair of eyes looking into this too

Which PR do you mean?

I was referring to extensibility of the implementation. So basically, have a look at this PR and check if extending it with the ideas I mentioned can be done easily or if this would cause major trouble. No need to actually implement anything for this yet.

typedef struct BacktracePanel_ {
Panel super;
const Process* process;
bool error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This boolean error flag seems to be unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used but in an inutile way... Good Catch!

@BenBE
Copy link
Member

BenBE commented Nov 28, 2024

I did a short test with the current state of the PR. I noticed the following issues so far:

  1. When configuring, it's not immediately obvious from the error message, which demangling library it is missing if you are e.g. missing libiberty-dev on Debian. Adding some wording of possible libraries into the error message might be helpful (reading the full output makes it obvious though, as the check just above tests for -liberty).
  2. The default text style in the backtrace window should be the default gray, not a shadow version of it. The current theme is kinda hard to read:
    image
  3. As seen in the screenshot, there is no filenames shown anywhere. I would have expected to at least see the module names avilable from the memory map of the affected process (/proc/<pid>/maps)
  4. With the default color being light grey, the shadow color may be reserved for things like the NULL mapping (0x0)
  5. If the offset is 0x0, it can be skipped after the name.
  6. For certain processes (tested and reproducible with teamviewerd so far) I receive a SIGABRT against htop.
  7. For processes with multiple LWP (threads) I still only receive one backtrace; would have expected one for each LWP.
  8. Process selection (SPACE) should be honored when present. If one or more processes are selected, the backtrace still looks at the cursor, not at the selection.

Update: Here's what gdb has to say about this crash:

$ sudo gdb ./htop 
Reading symbols from ./htop...
(gdb) r
Starting program: ./htop 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44
warning: 44     ./nptl/pthread_kill.c: No such file or directory
(gdb) bt full
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44
        tid = <optimized out>
        ret = 0
        pd = <optimized out>
        old_mask = {__val = {0}}
        ret = <optimized out>
        pd = <optimized out>
        old_mask = <optimized out>
        ret = <optimized out>
        tid = <optimized out>
        ret = <optimized out>
        resultvar = <optimized out>
        resultvar = <optimized out>
        __arg3 = <optimized out>
        __arg2 = <optimized out>
        __arg1 = <optimized out>
        _a3 = <optimized out>
        _a2 = <optimized out>
        _a1 = <optimized out>
        __futex = <optimized out>
        resultvar = <optimized out>
        __arg3 = <optimized out>
        __arg2 = <optimized out>
        __arg1 = <optimized out>
        _a3 = <optimized out>
        _a2 = <optimized out>
        _a1 = <optimized out>
        __futex = <optimized out>
        __private = <optimized out>
        __oldval = <optimized out>
#1  __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:78
No locals.
#2  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
No locals.
#3  0x00007ffff7a4519e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
        ret = <optimized out>
#4  0x00007ffff7a28902 in __GI_abort () at ./stdlib/abort.c:79
        save_stage = 1
        act = {__sigaction_handler = {sa_handler = 0x20, sa_sigaction = 0x20}, sa_mask = {__val = {152492813844671, 72062082414805760, 1661566579169759488, 93823560581142, 
              14445043518345882112, 93824992859660, 93824992859584, 140737488326320, 140737353001107, 140737488326320, 93824992857936, 0, 1, 140737488326384, 
              140737353184284, 140737488326368}}, sa_flags = -66016768, sa_restorer = 0x5594badd}
#5  0x0000555555588694 in fail () at XUtils.c:28
No locals.
#6  0x00005555555886bc in xMalloc (size=size@entry=40202694728) at XUtils.c:37
        data = <optimized out>
#7  0x000055555558039b in RichString_extendLen (this=0x7fffffffb6b0, len=1435810525) at RichString.c:29
No locals.
#8  RichString_setLen (this=0x7fffffffb6b0, len=1435810525) at RichString.c:57
No locals.
#9  0x0000555555580c2c in RichString_writeFromAscii (this=0x7fffffffb6b0, attrs=2102528, 
    data=0x7fff42a00010 " 0 0x0000780bc70f38e3 clock_nanosleep+0x63   -", ' ' <repeats 154 times>..., from=<optimized out>, len=1435810525) at RichString.c:147
        newLen = 1435810525
#10 RichString_appendnAscii (this=this@entry=0x7fffffffb6b0, attrs=2102528, 
    data=0x7fff42a00010 " 0 0x0000780bc70f38e3 clock_nanosleep+0x63   -", ' ' <repeats 154 times>..., len=1435810525) at RichString.c:262
No locals.
#11 0x00005555555892e1 in BacktraceFrame_display (super=0x555555a822b0, out=0x7fffffffb6b0) at BacktraceScreen.c:212
        frame = 0x555555a822b0
        printingHelper = <optimized out>
        displayOptions = <optimized out>
        functionName = <optimized out>
        maxFunctionNameLength = 22
        completeFunctionName = 0x555555a12b10 "clock_nanosleep+0x63"
        objectDisplayed = <optimized out>
        objectLength = <optimized out>
        maxAddrLen = <optimized out>
        line = 0x7fff42a00010 " 0 0x0000780bc70f38e3 clock_nanosleep+0x63   -", ' ' <repeats 154 times>...
        objectPathStart = 45
        len = <optimized out>
        colors = <optimized out>
#12 0x000055555557a98e in Panel_draw (this=this@entry=0x555555ac1f40, force_redraw=force_redraw@entry=true, focus=focus@entry=true, highlightSelected=true, 
    hideFunctionBar=false) at Panel.c:284
        itemObj = <optimized out>
        item = {chlen = 0, chptr = 0x7fffffffb6c0, chstr = {{attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 15872, chars = L"#\000\000\000", ext_color = 0}, 
            {attr = 15872, chars = L" \000\000\000", ext_color = 0}, {attr = 15872, chars = L"A\000\000\000", ext_color = 0}, {attr = 15872, chars = L"D\000\000\000", 
              ext_color = 0}, {attr = 15872, chars = L"D\000\000\000", ext_color = 0}, {attr = 15872, chars = L"R\000\000\000", ext_color = 0}, {attr = 15872, 
              chars = L"E\000\000\000", ext_color = 0}, {attr = 15872, chars = L"S\000\000\000", ext_color = 0}, {attr = 15872, chars = L"S\000\000\000", ext_color = 0}, {
              attr = 15872, chars = L" \000\000\000", ext_color = 0} <repeats 12 times>, {attr = 15872, chars = L"N\000\000\000", ext_color = 0}, {attr = 15872, 
              chars = L"A\000\000\000", ext_color = 0}, {attr = 15872, chars = L"M\000\000\000", ext_color = 0}, {attr = 15872, chars = L"E\000\000\000", ext_color = 0}, {
              attr = 15872, chars = L" \000\000\000", ext_color = 0} <repeats 19 times>, {attr = 15872, chars = L"P\000\000\000", ext_color = 0}, {attr = 15872, 
              chars = L"A\000\000\000", ext_color = 0}, {attr = 15872, chars = L"T\000\000\000", ext_color = 0}, {attr = 15872, chars = L"H\000\000\000", ext_color = 0}, {
              attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 23869072, chars = L"\000\x400000\000\x400000", ext_color = -17088}, {attr = 32767, 
              chars = L"\xf7f6d1a0翿\000\000", ext_color = 0}, {attr = 2049, chars = L"\000\xf6600190翿\xffffbcc0翿", ext_color = -17224}, {attr = 32767, 
              chars = L"\xf7f71240翿\x400000\000\x129e090", ext_color = 0}, {attr = 55596, chars = L"\000\xf7507688翿\xf7749a68翿", ext_color = 0}, {attr = 0, 
              chars = L"\000\000\000\000", ext_color = 0}, {attr = 23621608, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, 
              chars = L"\000\000\x559e6d08啕\x48bc5d", ext_color = 0}, {attr = 1436445960, chars = L"啕\x48bc5d\000\x55b0ced0啕", ext_color = 2056646}, {attr = 0, 
              chars = L"\xffffbd60翿\xffffcd90翿\xf7f5bad4", ext_color = 32767}, {attr = 0, chars = L"\000\x400000\000\x6f72702f\x30322f63", ext_color = 875968053}, {
              attr = 1869754166, chars = L"\x6f2f746f\x742f7470\x766d6165\x65776569\x76742f72", ext_color = 1852400223}, {attr = 1634038831, 
              chars = L"\x6569766d\x64726577\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0} <repeats 111 times>, {attr = 4278251341, 
              chars = L"*\020\000\xffffca30翿", ext_color = -13840}, {attr = 32767, chars = L"\xfc10aa00\xc8771a8b\000\000\x1f61c6", ext_color = 0}, {attr = 21482728, 
              chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\xffffca60翿\xf7f5b899翿", ext_color = 0}, {attr = 0, 
              chars = L"\x1f61c6\xffffcc20翿\x559e6d00啕", ext_color = 7}, {attr = 0, chars = L"\x147ccec\000\xffffcb00翿\xf7f627d5", ext_color = 32767}, {
              attr = 21482734, chars = L"\000\xff00ef4d*\x147cce8", ext_color = -16715955}, {attr = 42, chars = L"\x147cce8\000\x147cced\000\xffffcb58", ext_color = 32767}, 
            {attr = 4278251341, chars = L"*\x147cce8\000\x55b0ced0啕", ext_color = -13568}, {attr = 32767, chars = L"\xff00ef4d*\000\000\xfc10aa00", 
              ext_color = -931718517}, {attr = 4294953712, chars = L"翿\xf7a4542d翿\xffffcba0翿", ext_color = -134858069}, {attr = 32767, 
              chars = L"\000\000\000\000\020", ext_color = 0}, {attr = 0, chars = L"\000\020翿\xffffcb80翿", ext_color = -13504}, {attr = 32767, 
              chars = L"\xfc10aa00\xc8771a8b\x147ccf0\000\x1f61c6", ext_color = 0}, {attr = 21482736, chars = L"\000\000\000\xffffcba0翿", ext_color = 1437650640}, {
              attr = 21845, chars = L"\xffffcbb0翿\xf7f5b899翿\x147ccf1", ext_color = 0}, {attr = 1437650640, chars = L"\x1f61c6\x55b0ced0啕\xffffcd38翿", 
              ext_color = -13296}, {attr = 32767, chars = L"\a\000\xffffccc0翿\xf7f66692", ext_color = 32767}, {attr = 21482497, chars = L"\000\020\000\xffffcc10翿", 
              ext_color = 1437650640}, {attr = 21845, chars = L"\xffffd150翿\xffffcf40翿\xffffcd40", ext_color = 32767}, {attr = 4766813, 
              chars = L"\000\x147ccf8\000\x559e6d00啕", ext_color = 0}, {attr = 0, chars = L"\x559e6d00啕\x147ccf1\000*", ext_color = 0}, {attr = 4766773, 
              chars = L"\000\000\000\x147ccd9", ext_color = -2070802256}, {attr = 32765, chars = L"\xffffccc0翿\xffffd190翿\x48bc5e", ext_color = 0}, {attr = 4294967288, 
              chars = L"\xffffffff\020\000\000", ext_color = 0}, {attr = 130843, chars = L"\xffffd150翿\000翿\x559e6d00", ext_color = 21845}, {attr = 4294954312, 
              chars = L"翿\x849210b8翽\000", ext_color = 1}, {attr = 0, chars = L"\000\000\002\000\001", ext_color = 0}, {attr = 2, chars = L"\000\002\000\002", 
              ext_color = -2070802312}, {attr = 32765, chars = L"\000\000\004\000\002", ext_color = 0}, {attr = 5, chars = L"\000\002\000\x849210a0翽", ext_color = 0}, {
              attr = 0, chars = L"\a\000\002\000\b", ext_color = 0}, {attr = 2, chars = L"\000\t\000\002", ext_color = 10}, {attr = 0, chars = L"\002\000\v\000\002", 
              ext_color = 0}, {attr = 2224164992, chars = L"翽\000\000\x84921088翽", ext_color = 0}, {attr = 0, chars = L"\x84921090翽\000\000\x84921098", 
              ext_color = 32765}, {attr = 0, chars = L"\000\000\000\000", ext_color = -12800}, {attr = 32767, chars = L"\xffffd150翿\000\000", ext_color = 0}, {attr = 0, 
              chars = L"\000\001\000\xffffd0f0翿", ext_color = -134823047}, {attr = 32767, chars = L"\000\000\xf7fa3fa0翿", ext_color = 0}, {attr = 4294954688, 
              chars = L"翿\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {
              attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", 
              ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, 
              chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\020", 
              ext_color = 16843009}, {attr = 16843009, chars = L"\x1010101\x1010101\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {
              attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", 
              ext_color = 0}, {attr = 0, chars = L"\000\000\000\a", ext_color = 8}, {attr = 0, chars = L"\020\000\x1010101\x1010101\x1010101", ext_color = 16843009}, {
              attr = 768, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", 
              ext_color = -12112}, {attr = 32767, chars = L"\xfc10aa00\xc8771a8b\000\000\xffffff78", ext_color = -1}, {attr = 0, chars = L"\000\x55b0cec0啕\xffffd550翿", 
              ext_color = 2056646}, {attr = 0, chars = L"\xffffd0f0翿\xf7ab33ee翿\xffffd0e0", ext_color = 32767}, {attr = 2056646, chars = L"\000\000\000\x55aa2fd0啕", 
              ext_color = 9}, {attr = 0, chars = L"\x556a10e0啕\xffffd150翿\x55595aaa", ext_color = 21845}, {attr = 10, chars = L" \xffffd560翿\x55b0ced0啕", 
              ext_color = -8800}, {attr = 32767, chars = L"\x559e6d00啕\006\x1f61c6\xffffd5c8", ext_color = 32767}, {attr = 1, chars = L"\x137f\213\000\xc702a47b砋", 
              ext_color = 1436445952}, {attr = 21845, chars = L"\x55b0ced0啕\x849210b8翽", ext_color = 0}, {attr = 0, chars = L"\000\xffffd630翿\x555eebe2\x31335555", 
              ext_color = 0}, {attr = 3363248779, chars = L"\000\000\002\000\001", ext_color = 0}, {attr = 2, chars = L"\000\002\000\002", ext_color = -2070802312}, {
              attr = 32765, chars = L"\000\000\004\000\002", ext_color = 0}, {attr = 5, chars = L"\000\002\000\x849210a0翽", ext_color = 0}, {attr = 0, 
              chars = L"\a\000\002\000\b", ext_color = 0}, {attr = 2, chars = L"\000\t\000\002", ext_color = 10}, {attr = 0, chars = L"\002\000\v\000\002", ext_color = 0}, {
              attr = 2224164992, chars = L"翽\000\000\x84921088翽", ext_color = 0}, {attr = 0, chars = L"\x84921090翽\000\000\x84921098", ext_color = 32765}, {attr = 0, 
              chars = L"\000\000\000\000", ext_color = 1432278674}, {attr = 21845, chars = L"\x48bc35\000\x48bc5f\000", ext_color = 0}, {attr = 0, 
              chars = L"\000\000\000\000", ext_color = 1}, {attr = 72, chars = L"\000\000\000\000", ext_color = 32767}, {attr = 4159597532, 
              chars = L"翿\xffffdbc7翿\000啕", ext_color = 0}, {attr = 0, chars = L"\x555eeeae啕\000啕\n", ext_color = 0}, {attr = 16, 
              chars = L"0\xffffd560翿\xffffd470翿", ext_color = 0}, {attr = 0, chars = L"\003\005\x555b1a47啕\002", ext_color = 0}, {attr = 32, 
              chars = L"\000\x555eaee0啕\000\001", ext_color = 0}, {attr = 1, chars = L"!\000\001\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", 
              ext_color = 0}, {attr = 0, chars = L"\x555eae80啕\000\001", ext_color = 1}, {attr = 31, chars = L"\000\001\000\000", ext_color = 0}, {attr = 0, 
              chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {
              attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\xfc10aa00\xc8771a8b\x555eebe4\x31335555\xfc10aa00", ext_color = -931718517}, {
              attr = 30, chars = L"\000󴉀\000\036", ext_color = 0}, {attr = 0, chars = L"\x55aaf190啕\x555eec9f啕\xffffd500", ext_color = 32767}, {attr = 4155038888, 
              chars = L"翿\x555eebe5啕\x555eebe6啕", ext_color = -1}, {attr = 4294967295, chars = L"\000\000\003啕\xfc10aa00", ext_color = -931718517}, {attr = 6, 
              chars = L"\000\x555eecad啕\xffffd5e0翿", ext_color = -139189617}, {attr = 32767, chars = L"(0\xffffd5f0翿\xffffd530", ext_color = 32767}, {
              attr = 4159614398, chars = L"翿\000\000\xffffd880翿", ext_color = 30}, {attr = 0, chars = L"\x555ecf50啕\x72775f5f\x6d5f7061\x70636d65", ext_color = 121}, {
              attr = 0, chars = L"\000\000\000\000", ext_color = 0} <repeats 67 times>, {attr = 0, chars = L"\000\000\xffffdd50翿\xf7ab17fd", ext_color = 32767}, {
              attr = 0, chars = L"\000\000\000\000", ext_color = 0}, {attr = 0, chars = L"\006\000\004\000p", ext_color = 0}, {attr = 16, 
              chars = L"\000\000\000\xfc10aa00\xc8771a8b", ext_color = 0}}, highlightAttr = 0}
        itemLen = <optimized out>
        amt = <optimized out>
        i = 1
        line = 1
        size = <optimized out>
        scrollH = 0
        y = 1
        x = 0
        h = 42
        header_attr = <optimized out>
        headerLen = <optimized out>
        first = <optimized out>
        upTo = <optimized out>
        selectionColor = 15872
#13 0x00005555555815ca in ScreenManager_drawPanels (this=<optimized out>, focus=<optimized out>, force_redraw=<optimized out>) at ScreenManager.c:215
        panel = 0x555555ac1f40
        i = 0
        settings = <optimized out>
        nPanels = 1
        settings = <optimized out>
        nPanels = <optimized out>
        i = <optimized out>
        panel = <optimized out>
#14 ScreenManager_run (this=this@entry=0x5555559da100, lastFocus=lastFocus@entry=0x0, lastKey=lastKey@entry=0x0, name=name@entry=0x0) at ScreenManager.c:251
        prevCh = <optimized out>
        result = <optimized out>
        quit = false
        focus = <optimized out>
        panelFocus = <optimized out>
        settings = 0x5555555dc9d0
        oldTime = <optimized out>
        ch = <optimized out>
        closeTimeout = <optimized out>
        timedOut = <optimized out>
        redraw = <optimized out>
        force_redraw = <optimized out>
        rescan = <optimized out>
        sortTimeout = <optimized out>
        resetSortTimeout = 5
#15 0x000055555556b06b in actionBacktrace (st=<optimized out>) at Action.c:614
        process = <optimized out>
        panel = 0x555555ac1f40
        screenManager = 0x5555559da100
#16 0x0000555555576b99 in MainPanel_eventHandler (super=0x5555556992e0, ch=98) at MainPanel.c:116
        this = 0x5555556992e0
        host = 0x5555555cc410
        reaction = HTOP_OK
        result = IGNORED
        needReset = <optimized out>
        settings = <optimized out>
        ss = <optimized out>
#17 0x0000555555581719 in ScreenManager_run (this=this@entry=0x5555555de0f0, lastFocus=lastFocus@entry=0x0, lastKey=lastKey@entry=0x0, name=name@entry=0x0)
    at ScreenManager.c:334
        prevCh = 259
        result = IGNORED
        quit = false
        focus = <optimized out>
        panelFocus = <optimized out>
        settings = 0x5555555dc9d0
        oldTime = <optimized out>
        ch = <optimized out>
        closeTimeout = <optimized out>
        timedOut = <optimized out>
        redraw = true
        force_redraw = false
        rescan = <optimized out>
        sortTimeout = <optimized out>
        resetSortTimeout = 5
#18 0x000055555556f9d5 in CommandLine_run (argc=<optimized out>, argv=<optimized out>) at CommandLine.c:407
        lc_ctype = <optimized out>
        status = STATUS_OK
        flags = {pidMatchList = 0x0, commFilter = 0x0, userId = 4294967295, sortKey = 0, delay = -1, iterationsRemaining = -1, useColors = true, enableMouse = true, 
          treeView = false, allowUnicode = true, highlightChanges = false, highlightDelaySecs = -1, readonly = false}
        ut = 0x5555555de550
        dm = 0x0
        dc = 0x5555555cc2a0
        ds = 0x0
        host = 0x5555555cc410
        pt = 0x5555555dc390
        settings = 0x5555555dc9d0
        header = 0x5555555d0dd0
        panel = 0x5555556992e0
        state = {host = 0x5555555cc410, mainPanel = 0x5555556992e0, header = 0x5555555d0dd0, pauseUpdate = false, hideSelection = false, hideMeters = false}
        scr = 0x5555555de0f0
#19 0x00007ffff7a2a3b8 in __libc_start_call_main (main=main@entry=0x55555556aa70 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe398)
    at ../sysdeps/nptl/libc_start_call_main.h:58
        self = <optimized out>
        result = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737488348056, -625541430535108777, 1, 0, 93824992671064, 140737354125312, -625541430486874281, -625523329401075881}, 
              mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x1, 0x7fffffffe390}, data = {prev = 0x0, cleanup = 0x0, canceltype = 1}}}
        not_first_call = <optimized out>
#20 0x00007ffff7a2a47b in __libc_start_main_impl (main=0x55555556aa70 <main>, argc=1, argv=0x7fffffffe398, init=<optimized out>, fini=<optimized out>, 
    rtld_fini=<optimized out>, stack_end=0x7fffffffe388) at ../csu/libc-start.c:360
No locals.
#21 0x000055555556aaa5 in _start ()
No symbol table info available.
(gdb) 

Frame #8 looks suspicious:

#8  RichString_setLen (this=0x7fffffffb6b0, len=1435810525) at RichString.c:57

Why is it trying to create a string of 1.337GiB?

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Nov 29, 2024

  1. When configuring, it's not immediately obvious from the error message, which demangling library it is missing if you are e.g. missing libiberty-dev on Debian. Adding some wording of possible libraries into the error message might be helpful (reading the full output makes it obvious though, as the check just above tests for -liberty)

Yes, I agree. it's a good suggestion.

  1. The default text style in the backtrace window should be the default gray, not a shadow version of it. The current theme is kinda hard to read.
  1. With the default color being light grey, the shadow color may be reserved for things like the NULL mapping (0x0)

Yes, however, you emphasize a bug. The DYNAMIC_GRAY is used when a frame is NULL, that is not the case in your example. I fixed it, thanks.

  1. As seen in the screenshot, there is no filenames shown anywhere. I would have expected to at least see the module names avilable from the memory map of the affected process (/proc//maps)

In the beginning, I used eu-stack to get the backtrace of the application, which always gives the path. Then I switched to libunwind which provides very recently the ability to give the path: libunwind/libunwind#612. This PR was merged in September 2023 and added to v1.8.0 in January 2024. Depends on which version of lib you use, but It can be unavailable. However, as you said in your point 1, It could be a good idea to put a warning on the configuration if the libunwind is too old.

  1. If the offset is 0x0, it can be skipped after the name.

Even if it's beak the homogeneity?

  1. For certain processes (tested and reproducible with teamviewerd so far) I receive a SIGABRT against htop.

Why is it trying to create a string of 1.337GiB?

It's possible that libunwind provides corrupted data, I had some crashes also due to libunwind.

  1. For processes with multiple LWP (threads) I still only receive one backtrace; would have expected one for each LWP.

Yes it was the first behavior, and when I switched to libunwind, I deleted it because I considered if you want the backtrace of a thread, you can choose the thread. Moreover, certain applications (like Firefox) have a lot of threads that can slow the application and htop. However, what we can do is to make in the bottom bar the ability to show all threads or not.

  1. Process selection (SPACE) should be honored when present. If one or more processes are selected, the backtrace still looks at the cursor, not at the selection

I just discovered this functionality of htop 😄. From what I see, certain functionalities like showing the environment don't do that. It's a great suggestion but it's needed a little bit of work.

Very thank you @BenBE for these suggestions, for your feedback and for all the code review. Very thank you also @Explorer09 for your code review

@BenBE
Copy link
Member

BenBE commented Nov 29, 2024

  1. When configuring, it's not immediately obvious from the error message, which demangling library it is missing if you are e.g. missing libiberty-dev on Debian. Adding some wording of possible libraries into the error message might be helpful (reading the full output makes it obvious though, as the check just above tests for -liberty)

Yes, I agree. it's a good suggestion.

  1. As seen in the screenshot, there is no filenames shown anywhere. I would have expected to at least see the module names avilable from the memory map of the affected process (/proc//maps)

In the beginning, I used eu-stack to get the backtrace of the application, which always gives the path. Then I switched to libunwind which provides very recently the ability to give the path: libunwind/libunwind#612. This PR was merged in September 2023 and added to v1.8.0 in January 2024. Depends on which version of lib you use, but It can be unavailable. However, as you said in your point 1, It could be a good idea to put a warning on the configuration if the libunwind is too old.

I'd have to recheck which version of the involved libs I have, but given I run a quite recent Ubuntu release (newer than LTS), we should at least fetch information from the memory map (reading the names from there is (mostly) free), as the LTS will not have this otherwise for a few years.

Versions:

  • libiberty-dev: 20240117-1build1
  • libunwind-dev + libunwind8: 1.6.2-3.1
  1. If the offset is 0x0, it can be skipped after the name.

Even if it breaks the homogeneity?

Mostly was a note/suggestion.

At least for things like ???+0x0 just looks strange. Same for 0x12345678+0x0 if there's no name known.

For things like main+0x0 vs. main it's a matter of preference. Also just something I noticed while giving the PR a quick test drive.

  1. For certain processes (tested and reproducible with teamviewerd so far) I receive a SIGABRT against htop.

Why is it trying to create a string of 1.337GiB?

It's possible that libunwind provides corrupted data, I had some crashes also due to libunwind.

Would be good if we can somehow avoid crashing even with somewhat corrupted data. Assume things to be untrusted, as you are operating on memory outside your control (other processes).

  1. For processes with multiple LWP (threads) I still only receive one backtrace; would have expected one for each LWP.

Yes it was the first behavior, and when I switched to libunwind, I deleted it because I considered if you want the backtrace of a thread, you can choose the thread. Moreover, certain applications (like Firefox) have a lot of threads that can slow the application and htop. However, what we can do is to make in the bottom bar the ability to show all threads or not.

👍

  1. Process selection (SPACE) should be honored when present. If one or more processes are selected, the backtrace still looks at the cursor, not at the selection

I just discovered this functionality of htop 😄. From what I see, certain functionalities like showing the environment don't do that. It's a great suggestion but it's needed a little bit of work.

NP. Also if you decided to have this added in a later/separate PR I'd be totally fine with splitting this too.

@MrCirdo
Copy link
Contributor Author

MrCirdo commented Dec 8, 2024

At least for things like ???+0x0 just looks strange. Same for 0x12345678+0x0 if there's no name known.

This is my wish. Having a correct +0x0 is very rare (maybe impossible, my idea for having a +0x0 is to use assembly directly but I don't test it 😄), so it is here to say there is something wrong that happend. I also ensure it displays +0x0 to not break the offsets' homogeneity.

Would be good if we can somehow avoid crashing even with somewhat corrupted data. Assume things to be untrusted, as you are operating on memory outside your control (other processes).

It's a great suggestion to put safe-guard. I'll look at it.
For the crash, I'll dig to see what happened (if I have the time).

I'd have to recheck which version of the involved libs I have, but given I run a quite recent Ubuntu release (newer than LTS), we should at least fetch information from the memory map (reading the names from there is (mostly) free), as the LTS will not have this otherwise for a few years.

Yes, and as I see there is some code in htop that reads /proc/<pid>/maps. I'll do in another PR.

MrCirdo and others added 5 commits December 8, 2024 18:24
Co-authored-by: Benny Baumann <[email protected]>
Co-authored-by: Kang-Che Sung <[email protected]>
Co-authored-by: Benny Baumann <[email protected]>
Co-authored-by: Kang-Che Sung <[email protected]>
Co-authored-by: Benny Baumann <[email protected]>
Co-authored-by: Kang-Che Sung <[email protected]>
Co-authored-by: Benny Baumann <[email protected]>
Co-authored-by: Kang-Che Sung <[email protected]>
Co-authored-by: Benny Baumann <[email protected]>
Co-authored-by: Kang-Che Sung <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature Completely new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants