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 5 commits into
base: main
Choose a base branch
from
Open

Add Backtrace Screen #1270

wants to merge 5 commits into from

Conversation

MrCirdo
Copy link

@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
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
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
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
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
for (size_t i = 0; i < backtraceScreen->nbBacktraces; i++) {
Backtrace *backtrace = &backtraceScreen->backtraces[i];
char *tgidStr = NULL;
if (!isThread) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (!isThread) {
if (!isThread) {

BacktraceScreen.c Show resolved Hide resolved
BacktraceScreen.c Show resolved Hide resolved
BacktraceScreen.h Show resolved Hide resolved
@MrCirdo
Copy link
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
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
@@ -561,6 +561,39 @@ case "$enable_unwind_ptrace" in
;;
esac

AC_ARG_ENABLE([libiberty],
Copy link
Contributor

@Explorer09 Explorer09 Mar 16, 2024

Choose a reason for hiding this comment

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

Autoconf naming convention typically avoids "--enable-LIBRARY" for library support. You have two ways to fix this:

  1. Use "--enable-FEATURE" naming such as "--enable-demangle". I personally recommend this way as people can add demangling support for other OSes.
  2. Change the option name to "--with-libiberty". See AC_ARG_WITH in the Autoconf manual to know what I mean.

Copy link
Author

Choose a reason for hiding this comment

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

I choose the first one. I let you solve the conversation if the change is correct for you

Copy link
Contributor

@Explorer09 Explorer09 Mar 30, 2024

Choose a reason for hiding this comment

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

(Please help me close this conversation. I cannot close it myself and there's another conversation below this one. Thus this conversation can be closed as resolved/ outdated.)

#include "XUtils.h"
#include "errno.h"

#include <libiberty/demangle.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

You should guard this include line with #ifdef HAVE_LIBIBERTY.

Copy link
Author

Choose a reason for hiding this comment

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

Well, See!

Copy link
Author

Choose a reason for hiding this comment

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

It's fixed

Copy link
Contributor

Choose a reason for hiding this comment

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

Coding style. Please put the conditional include lines after the mandatory/always include lines.

@MrCirdo MrCirdo force-pushed the main branch 2 times, most recently from c53af06 to 792bdba Compare March 16, 2024 20:46
#include "XUtils.h"
#include "errno.h"

#include <libiberty/demangle.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

Coding style. Please put the conditional include lines after the mandatory/always include lines.


const pid_t pid = Process_getPid(this->process);

if (pid == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it intentional to compare (pid == 0) only or is it (pid <= 0)? (PID is a signed type. Negative PIDs are reserved for references to process groups in most Unix-like systems.)

Copy link
Author

Choose a reason for hiding this comment

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

Okay, If I understand correctly what you said, a negative PID can represent a group of processes, but can Process_getPid return a group of processes (and return a negative pid)?
But It makes sense to attach to one process/thread and not a group of processes, so it should be pid <= 0.

char* functionName;
bool isSignalFrame;

bool isError;
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't quite get the idea why you need this "isError" boolean flag. Is it not enough to check whether the "error" pointer is NULL?

Copy link
Author

Choose a reason for hiding this comment

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

I can't entirely agree with what I did about error management. I mean, the structure Frame should contain only data associated with the frame. And It doesn't make sense for me to have a field error representing a general error on a frame. I have to try other ways to show an error.

configure.ac Outdated
@@ -561,6 +561,37 @@ case "$enable_unwind_ptrace" in
;;
esac

AC_ARG_ENABLE([iberty],
Copy link
Contributor

Choose a reason for hiding this comment

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

No. libiberty isn't just about demangling. libiberty is a generic support library for the GNU toolchain in which demangling is one of the main features. I said to name the keyword after the feature, that is, "--enable-demangle". Maybe we can allow specifications like --enable-demangle=libiberty in the future if we support other library/API for the demangling purpose.

Copy link
Contributor

Choose a reason for hiding this comment

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

@MrCirdo Just to give you an idea: When an optional feature introduces a library dependency, we name the "--enable-" option after the feature, not after the library. For example the --enable-unicode option in htop and not --enable-libncursesw (it's not --enable-ncursesw either). The "--with-" option naming is to specify dependencies, thus --with-libncursesw would make sense.

  • For software that provides the library rather than depend on them, --enable-libXXX would be used. Example: In GCC's build system there are --enable-libstdcxx, --enable-libatomic, --enable-libquadmath etc. because those libraries are provided by GCC.

Copy link
Author

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 the explanation @Explorer09. I will try one more time 😄

@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
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
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

Action.c Outdated Show resolved Hide resolved
Action.c Outdated Show resolved Hide resolved
Action.c Outdated Show resolved Hide resolved
BacktraceScreen.c Show resolved Hide resolved
configure.ac Outdated
;;
esac
if test "x$enable_backtraces" = xunwind-ptrace; then
AC_DEFINE([BACKTRACE_ENABLED], [1], [Define if the backtraces is enabled])
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer BACKTRACE_SUPPORT. Maybe others have other suggestions?

The name BACKTRACE_ENABLED somehow does not really convey what that switch is about. Also it might be mistaken for some misnamed --enable-??? flag where naming got mixed up.

Copy link
Contributor

Choose a reason for hiding this comment

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

How about just name it ENABLE_BACKTRACE?
Same wording for all --enable-* configure options in Autoconf.

Copy link
Contributor

Choose a reason for hiding this comment

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

And by the way, I don't like the idea of using plural for the "--enable-backtraces" option. The term "backtrace" may be used as an adjective or a verb, and the singular/infinitive form is more widely seen in web searches.

Copy link
Author

Choose a reason for hiding this comment

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

I prefer also BACKTRACE_SUPPORT. I'll change.
For the plural of backtrace, I also agree with you @Explorer09. --enable-backtrace can mean enable the support of backtrace, so it's singular.

Copy link
Member

Choose a reason for hiding this comment

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

Any objections to --enable-backtrace-support then? I know it's kinda long, but it avoids the issue with postfixing the enable

Copy link
Member

Choose a reason for hiding this comment

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

I think --enable-backtrace is best as we don't do --enable-unwind-support etc. either

The macro names seem to be commonly HAVE_*. I would let @BenBE do the final call here as he is typically closest to the coding style.

Greets
/DLange

Copy link
Member

Choose a reason for hiding this comment

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

Following up internally, we'll go with:

  • --enable-backtrace
  • HAVE_BACKTRACE

Though I'm not fully happy with this, this is, based on discussions, the most consistent way to go forward in this case IMO. It also matches best with what we already use for other feature flags in our code.

Copy link
Author

Choose a reason for hiding this comment

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

Just --enable-backtrace or --enable-backtrace=unwind-ptrace ? I'm confused.
It makes sense to implement --enable-backtrace=unwind-ptrace. The methods could be different for the other platforms.

Copy link
Contributor

Choose a reason for hiding this comment

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

@MrCirdo Implement both. Let --enable-backtrace translate to --enable-backtrace=unwind-ptrace in Linux, and --enable-backtrace=no for other platforms. In case you don't understand how to use Autoconf macros, feel free to ask and I can offer help when I can.

Copy link
Author

Choose a reason for hiding this comment

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

Oh okay, I see. I'll try.

pcp/Platform.c Show resolved Hide resolved
BacktraceScreen.h Show resolved Hide resolved
BacktraceScreen.h Outdated Show resolved Hide resolved
BacktraceScreen.h Show resolved Hide resolved
Comment on lines +26 to +28
size_t address;
size_t offset;
char* functionName;
Copy link
Member

Choose a reason for hiding this comment

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

Preferably this should split the library from the function name as separate fields. Also, if available through debug symbols, file+line number information are commonly useful.

@MrCirdo MrCirdo force-pushed the main branch 2 times, most recently from bcf3fc1 to 6b61be2 Compare April 10, 2024 20:02
[enable printing backtraces.])],
[],
[enable_backtrace=no])
case "$enable_backtrace" in
Copy link
Contributor

@Explorer09 Explorer09 Apr 10, 2024

Choose a reason for hiding this comment

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

@MrCirdo
Code simplification and bug fix:

  • Since you are going to link to both libunwind-ptrace and libunwind-generic, it is unnecessary to use two AC_CHECK_LIB macros and the way you wrote it won't work.
  • AC_CHECK_HEADERS([libunwind-ptrace.h], ...) and AC_CHECK_HEADERS([libunwind/libunwind-ptrace.h], ...) would define different C macros. It doesn't work the way you think. I correct it so that it works the way you intended.
if test "x$enable_backtrace" = xyes; then
   case $my_htop_platform in
      linux)
         enable_backtrace=unwind-ptrace
         ;;
      *)
         AC_MSG_ERROR([backtrace feature not implemented for the '$my_htop_platform' platform])
         ;;
   esac
fi

case "$enable_backtrace" in
   no)
      ;;
   unwind-ptrace)
      AC_CHECK_LIB([unwind-ptrace], [_UPT_create], [], [AC_MSG_ERROR([can not find required library libunwind-ptrace and libunwind-generic])], [-lunwind-generic])
      AC_CHECK_HEADERS([libunwind-ptrace.h], [], [
         CPPFLAGS="$CPPFLAGS -I/usr/include/libunwind"
         AC_CHECK_HEADERS([libunwind-ptrace.h], [], [AC_MSG_ERROR([can not find required header file libunwind-ptrace.h])])
      ])
      ;;
   *)
      AC_MSG_ERROR([bad value '$enable_backtrace' for --enable-backtrace])
      ;;
esac
if test "x$enable_backtrace" != xno; then
   AC_DEFINE([HAVE_BACKTRACE], [1], [Define if the backtrace feature is enabled])
fi

Copy link
Author

Choose a reason for hiding this comment

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

Oh okay, it's much clearer than what I wrote 😄
For some obscure linking error, two AC_CHECK_LIB are needed.
Thank you very much @Explorer09

configure.ac Outdated
[enable demangling support for backtraces @<:@default=check@:>@])],
[],
[enable_demangling=check])
case "$enable_demangling" in
Copy link
Contributor

Choose a reason for hiding this comment

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

My attempt to rewrite the code:

have_libiberty=no
case $enable_demangling in
   check|yes|libiberty)
      AC_CHECK_LIB([iberty], [cplus_demangle], [have_libiberty=yes], [
         if test "x$enable_demangling" = xlibiberty; then
            AC_MSG_ERROR([--enable-demangling specified but libiberty not found])
         fi
      ])
      if test "x$have_libiberty" = xyes; then
         AC_CHECK_HEADERS([demangle.h], [], [
dnl FIXME: do i need to restore $CPPFLAGS after this?
            CPPFLAGS="$CPPFLAGS -I/usr/include/libiberty"
            AC_CHECK_HEADERS([demangle.h], [], [
               have_libiberty=no
               if test "x$enable_demangling" = xlibiberty; then
                  AC_MSG_ERROR([--enable-demangling specified but <demangle.h> not found])
               fi
            ])
         ])
      fi
      if test "x$have_libiberty" = xyes; then
         enable_demangling=libiberty
      fi
      ;;
esac

dnl have_libXXX=no
dnl case $enable_demangling in
dnl    check|yes|libXXX)
dnl       AC_CHECK_LIB([XXX], [funcname], [have_libXXX=yes], [
dnl          if test "x$enable_demangling" = xlibXXX; then
dnl             AC_MSG_ERROR([--enable-demangling specified but libXXX not found])
dnl          fi
dnl       ])
dnl       if test "x$have_libXXX" = xyes; then
dnl          AC_CHECK_HEADERS([XXX.h], [], [
dnl             have_libXXX=no
dnl             if test "x$enable_demangling" = xlibXXX; then
dnl                AC_MSG_ERROR([--enable-demangling specified but <XXX.h> not found])
dnl             fi
dnl          ])
dnl       fi
dnl       if test "x$have_libXXX" = xyes; then
dnl          enable_demangling=libXXX
dnl       fi
dnl       ;;
dnl esac

case $enable_demangling in
   check)
      enable_demangling=no
      ;;
   yes)
      AC_MSG_ERROR([cannot find any library for the backend supported by --enable-demangling])
      ;;
   *)
      AC_MSG_ERROR([bad value '$enable_demangling' for --enable-demangling])
      ;;
esac

Copy link
Author

Choose a reason for hiding this comment

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

Thank you very much @Explorer09.
Your code inspired me to improve what I wrote.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oops. I made a mistake in the example code given above. It should be written like this instead:

case $enable_demangling in
   libiberty)
      AC_DEFINE([HAVE_DEMANGLING], [1], [Define to 1 if the demangling is supported])
      ;;
   check)
      enable_demangling=no
      ;;
   yes)
      AC_MSG_ERROR([cannot find any library for the backend supported by --enable-demangling])
      ;;
   *)
      AC_MSG_ERROR([bad value '$enable_demangling' for --enable-demangling])
      ;;
esac

@MrCirdo MrCirdo force-pushed the main branch 2 times, most recently from 747a2c0 to 4bd4f4c Compare April 24, 2024 18:13
Action.c Outdated Show resolved Hide resolved
Action.h Outdated
@@ -6,6 +6,7 @@ htop - Action.h
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
Copy link
Member

Choose a reason for hiding this comment

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

This should go into Action.c and other files using Action.h. Otherwise you can't guarantee that this is the first overall included header.

Copy link
Author

Choose a reason for hiding this comment

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

Oh okay, I get it. It must be in c to be sure it is the first include.

BacktraceScreen.c Show resolved Hide resolved
BacktraceScreen.h Outdated Show resolved Hide resolved
BacktraceScreen.h Outdated Show resolved Hide resolved
README.md Outdated
Comment on lines 147 to 149
* `--enable-iberty`:
enable the demangling support for the backtraces
- default: *no*
Copy link
Member

Choose a reason for hiding this comment

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

Documentation out of sync with implementation.

configure.ac Outdated
Comment on lines 566 to 587
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <libunwind-ptrace.h>
#ifndef unw_get_elf_filename
# error 'unw_get_elf_filename' not defined
#endif
]])], [AC_DEFINE([HAVE_LIBUNWIND_ELF_FILENAME], [1], [Define if libunwind has unw_get_elf_filename])], [])
Copy link
Member

Choose a reason for hiding this comment

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

Isn't there some existing AutoConf magic to do this?

Copy link
Author

Choose a reason for hiding this comment

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

I cannot use AC_CHECK_LIB because unw_get_elf_filename is a macro. I searched and it's the only method I found.

Copy link
Contributor

Choose a reason for hiding this comment

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

@MrCirdo Use AC_LINK_IFELSE then, and add a comment that unw_get_elf_filename may be a macro.

Copy link
Author

Choose a reason for hiding this comment

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

It's done. Thank you @Explorer09

Copy link
Contributor

Choose a reason for hiding this comment

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

No no no. The reason for AC_LINK_IFELSE is that it checks the linking with the library as well as compiling. So you should write a simple program that calls the function (be it a macro or not). You can use LDFLAGS and LIBS variables along with AC_LINK_IFELSE.

Copy link
Author

@MrCirdo MrCirdo Jun 16, 2024

Choose a reason for hiding this comment

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

Oh okay, I see. If I understand correctly. I wrote that :

if test "x$enable_backtrace" = xunwind-ptrace; then
   # Check if the macro unw_get_elf_filename exists
   AC_LINK_IFELSE(
     [AC_LANG_PROGRAM(
       [[#include <libunwind-ptrace.h>]],
       [[unw_get_elf_filename(0, 0, 0, 0);]]
     )],
     [AC_DEFINE([HAVE_LIBUNWIND_ELF_FILENAME], [1], [Define if libunwind has unw_get_elf_filename])],
     []
   )
fi

It works but is it correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

@MrCirdo You partly get the idea. This checks if the macro exists and whether it can link to libunwind successfully with the said function.

Allow me to polish the code a bit (I add a AC_MSG_CHECKING so that when the compiling fails, it's easier to look up the error in the config log file; also I add type casts which might be helpful):

if test "x$enable_backtrace" = xunwind-ptrace; then
   AC_MSG_CHECKING([if libunwind has unw_get_elf_filename])
   AC_LINK_IFELSE(
      [AC_LANG_PROGRAM(
         [[/* unw_get_elf_filename might exist as a macro */
         #include <libunwind-ptrace.h>]],
         [[unw_get_elf_filename((unw_cursor_t*)0, (char*)0, (size_t)0, (unw_word_t*)0);]]
      )],
      [AC_DEFINE([HAVE_LIBUNWIND_ELF_FILENAME], [1], [Define if libunwind has unw_get_elf_filename])
      AC_MSG_RESULT(yes)],
      [AC_MSG_RESULT(no)]
   )
fi

Copy link
Author

Choose a reason for hiding this comment

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

Thank you very much @Explorer09, I added your code 😄
I pushed some changes about the demangling (strongly inspired by your code). Is it good for you?

linux/Platform.c Outdated Show resolved Hide resolved
linux/Platform.c Show resolved Hide resolved
linux/Platform.c Show resolved Hide resolved
configure.ac Outdated
[enable_demangling=no])
case "$enable_demangling" in
check|yes|libiberty)
enable_demangling=libiberty
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't set enable_demangling=libiberty right now. It would affect the case...esac logic in the next block. Set enable_demangling=libiberty only when the check is succeeded.
The logic is this: Update the enable_demangling value when a library is found to confirm we are going to use it. If enable_demangling remains check or yes, test for another library, until there is none to test. Then, either update the enable_demangling to no or generate an error.

configure.ac Outdated
old_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -I/usr/include/libiberty"
AC_CHECK_HEADERS([libiberty/demangle.h], [], [
enable_demangling=no
Copy link
Contributor

Choose a reason for hiding this comment

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

Likewise. It is intentional in my code not to set enable_demangling=no. Otherwise you won't get the error when libiberty is not found.

@MrCirdo MrCirdo force-pushed the main branch 4 times, most recently from dbea72f to 07f612d Compare June 16, 2024 20:11
MrCirdo and others added 5 commits July 9, 2024 21:36
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]>
@MrCirdo
Copy link
Author

MrCirdo commented Jul 9, 2024

This is what it looks like now :
image
Do you have any recommendation?

@BenBE
Copy link
Member

BenBE commented Jul 9, 2024

As you already have the various fields separated it would be nice to show this kinda tabulated. Also having addr module file line function+offs is a better order for the information (with unavailable items left blank). Maybe have a look at the Open Files list view for how a header could be handled.

Also with long filenames (especially on Nix) it would be nice to have this vie care about the "hide program path" setting and the "highlight basename"/"mark outdated" settings.

@MrCirdo
Copy link
Author

MrCirdo commented Jul 10, 2024

Also with long filenames (especially on Nix) it would be nice to have this vie care about the "hide program path" setting and the "highlight basename"/"mark outdated" settings.

That's a good idea!

As you already have the various fields separated it would be nice to show this kinda tabulated. Also having addr module file line function+offs is a better order for the information (with unavailable items left blank). Maybe have a look at the Open Files list view for how a header could be handled.

In my original draft, it was tabulated. But I see it's a good idea.
Currently, the lib unwind cannot get the line and in general programs are compiled without debug symbols. So I'm afraid that the line column will be blank

@BenBE
Copy link
Member

BenBE commented Jul 11, 2024

Currently, the lib unwind cannot get the line and in general programs are compiled without debug symbols. So I'm afraid that the line column will be blank

Depending on how much dynamic you want to implement, you could hide the file+line columns if none of the rows includes information to display for those. Sometimes you have debug information available or even a service that can pull such information on-the-fly from separate debug info caches (although such long-lasting tasks should be on-demand). Thinking of fetching debug symbols like GDB does (based on buildinfo data embedded in the binaries). But that's something for a later improvement.

@MrCirdo
Copy link
Author

MrCirdo commented Jul 12, 2024

Thinking of fetching debug symbols like GDB does (based on buildinfo data embedded in the binaries). But that's something for a later improvement.

That's a good idea too. I note that.

Also having addr module file line function+offs is a better order for the information (with unavailable items left blank).

I'm inspired by the output of GDB. I prefer this layout.

So now, it's look like :
image

I have small improvements to do and I'll push the code. Is it better now?

@Explorer09
Copy link
Contributor

Explorer09 commented Jul 13, 2024

I'm inspired by the output of GDB. I prefer this layout.

So now, it's look like : image

I have small improvements to do and I'll push the code. Is it better now?

  1. There are unnecessary zero digits in the ADDRESS column. Perhaps it's good to give the column a dynamic width.
  2. What does the "+number" after the symbol name represents? Is it in lines or in bytes? Is it base 10 or base 16?

@BenBE
Copy link
Member

BenBE commented Jul 13, 2024

I'm inspired by the output of GDB. I prefer this layout.
So now, it's look like : image
I have small improvements to do and I'll push the code. Is it better now?

#NB should probably be Frame if you want to stick with the GDB terminology.

  1. There are unnecessary zero digits in the ADDRESS column. Perhaps it's good to give the column a dynamic width.

I think if we trim leading zeros for ADDRESS it's best to right-align that column. Furthermore I second that suggestion with the dynamic width.

  1. What does the "+number" after the symbol name represents? Is it in lines or in bytes? Is it base 10 or base 16?

The +number is the offset (in bytes) from the start of the function. Should be marked as hex by explicit 0x prefix IMO even though offsets are usually presented as hex when referring to memory addresses.

Okay, now the questions from my side:

  1. Do the colors have a special meaning? Like does the color of addresses encode memory protection stuff/mapping status?
  2. Given the function name can be quite large, wouldn't it be better to have it shown after the PATH column?
  3. Did you include the coloring for modules based on its deleted/obsolete status?
  4. The items in the menu bar should be much shorter. Demangle/Raw for the first and Full path/Basename fully suffice.
  5. Note that the shortcut for abbreviating the path names is p everywhere else.

@MrCirdo
Copy link
Author

MrCirdo commented Jul 16, 2024

There are unnecessary zero digits in the ADDRESS column. Perhaps it's good to give the column a dynamic width.

I think if we trim leading zeros for ADDRESS it's best to right-align that column. Furthermore I second that suggestion with the dynamic width.

Yes there are a lot of zeros because my computer is 64-bit, so the address has 16 digits. However, you point out something interesting. What if htop is running on a 16-bit processor? And it's a good idea to have a dynamic column to handle this situation. Now I have multiple options to make this column dynamic. There is the right alignment (as you said @BenBE) but there is also zero-padded dynamic alignment. Let me try both.

What does the "+number" after the symbol name represents? Is it in lines or in bytes? Is it base 10 or base 16?

The +number is the offset (in bytes) from the start of the function. Should be marked as hex by explicit 0x prefix IMO even though offsets are usually presented as hex when referring to memory addresses.

Yes it's the offset in the functions. It's a good idea to show it with a hex representation. Fun fact GDB doesn't show it 😄

#NB should probably be Frame if you want to stick with the GDB terminology.

I'm concerned about the size of the name of this column. Because generally, there are less than 100 frames. And I can put FRAME or NB FRAME however, I'm afraid there will be a waste of space.

  1. Do the colors have a special meaning? Like does the color of addresses encode memory protection stuff/mapping status?

Euh no, I like colors so I tried to show the color that renders more beautiful and more visible.

  1. Given the function name can be quite large, wouldn't it be better to have it shown after the PATH column?

Yes, I can try to see what it would look like. In the GDB printing, it's at the end. This is why 😄

  1. Did you include the coloring for modules based on its deleted/obsolete status?

Euh no, but I'm not sure what do you want to say?

  1. The items in the menu bar should be much shorter. Demangle/Raw for the first and Full path/Basename fully suffice.

Yes It's definitely better.

@Explorer09
Copy link
Contributor

What if htop is running on a 16-bit processor?

Nope. htop doesn't support any 16-bit operating system at the moment, and it's unlikely to ever happen. You might be referring to 32-bit instead.

Euh no, I like colors so I tried to show the color that renders more beautiful and more visible.

The principle is, if there is any special information conveyed through color alone, it should be documented, and provide an alternative representation for monochrome terminals (in other words, think of colorblind accessibility).

@BenBE
Copy link
Member

BenBE commented Jul 16, 2024

#NB should probably be Frame if you want to stick with the GDB terminology.

I'm concerned about the size of the name of this column. Because generally, there are less than 100 frames. And I can put FRAME or NB FRAME however, I'm afraid there will be a waste of space.

We always can just call that column # or Frm, with # being the preferred one.

  1. Do the colors have a special meaning? Like does the color of addresses encode memory protection stuff/mapping status?

Euh no, I like colors so I tried to show the color that renders more beautiful and more visible.

If you do not have special meaning for a color you shouldn't be using one unnecessarily. It's not about being as colorful as possible, but to convey information in a concise and structured way.

  1. Did you include the coloring for modules based on its deleted/obsolete status?

Euh no, but I'm not sure what do you want to say?

Have a look at the options Highlight program basename and Highlight out-dated/removed programs / libraries in the settings dialog. Effect can be seen on the main process list in the COMMAND column.

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