Skip to content

Conversation

@Explorer09
Copy link
Contributor

@Explorer09 Explorer09 commented Nov 15, 2025

This branch is experimental and related to #1270 (the backtrace screen feature).

I've written and improved the configure script so that it can check libunwind-ptrace and libiberty for the backtrace feature proposed in #1270.

The changes come with two parts:

The first part can be reviewed and cherry-picked into main early. It renames the configure option --enable-unwind to --with-libunwind to better reflect it's purpose. The old option name is preserved for compatibility but will trigger warnings when used.

The second part consists of several commits that add the new configure options --enable-backtrace and --enable-demangling and the checking code of libunwind-ptrace and libiberty. The code might look large and complicated, but I've tried a lot on the usability and correctness of the check. For example this libunwind-ptrace check can work with and without pkg-config, and I tried to ensure the cplus_demangle() function has a correct prototype.

The libunwind-ptrace and libiberty libraries can be detected both in Linux and in FreeBSD. However, I haven't ported the backtrace screen code from @MrCirdo to ensure they really build, especially in FreeBSD.

@BenBE BenBE added enhancement Extension or improvement to existing feature code quality ♻️ Code quality enhancement build system 🔧 Affects the build system rather then the user experience labels Nov 15, 2025
@BenBE BenBE added this to the 3.5.0 milestone Nov 15, 2025
@BenBE
Copy link
Member

BenBE commented Nov 16, 2025

Can you note, which commits for the first vs. second part? I assume the first commit ("Rename *" for the first and the remaining 4 later?

I think we can also do this all at once. But I'm ope on that front.

@Explorer09
Copy link
Contributor Author

Explorer09 commented Nov 16, 2025

Can you note, which commits for the first vs. second part? I assume the first commit ("Rename *" for the first and the remaining 4 later?

Yes, the first commit is the option rename, and the remaining 4 commits are the new feature / configure options.

The reason I suggest the rename is that --enable-backtrace=unwind-ptrace will depend on the --with-libunwind option and it's hard to split the two apart. That means the --enable-backtrace=unwind-ptrace --without-libunwind combination will being you an error.

@BenBE
Copy link
Member

BenBE commented Nov 16, 2025

Do we have alternative backends for backtracing/demangling besides unwind-ptrace and iberty? Given there's both an unwind implementation in LLVM and GCC, what else are sensible alternatives that warrent implementation of the --enable-backtrace switch as --enable-backtrace=unwind (if I saw that correctly in the source)?

@Explorer09
Copy link
Contributor Author

Do we have alternative backends for backtracing/demangling besides unwind-ptrace and iberty? Given there's both an unwind implementation in LLVM and GCC, what else are sensible alternatives that warrent implementation of the --enable-backtrace switch as --enable-backtrace=unwind (if I saw that correctly in the source)?

Well, I don't know what other libraries are possible for the backtrace feature, but I leave room for those new backends.

For the demangling function, I can see libdemangle from Solaris / Sun Studio as a possible alternative, but I didn't check that yet. It's better for @MrCirdo 's code (#1270) get merged first before considering alternatives.

@BenBE
Copy link
Member

BenBE commented Nov 16, 2025

NP. No need to decide on all the possible backends and variants now. That's something we can leave open for the first implementation. Priority is getting things work; make them flexible and fast is the next step. No need to over-engineer things from the get-go. I just wanted to evaluate if there's a reasonable need for allowing the backends for backtraces and demangling to be replaced.

@MrCirdo MrCirdo mentioned this pull request Nov 16, 2025
@Explorer09 Explorer09 force-pushed the configure-enable-backtrace branch 9 times, most recently from a964363 to 798b603 Compare November 23, 2025 01:38
@Explorer09 Explorer09 marked this pull request as ready for review November 23, 2025 01:44
@Explorer09 Explorer09 force-pushed the configure-enable-backtrace branch from 798b603 to 9ced4f4 Compare November 23, 2025 03:27
@Explorer09
Copy link
Contributor Author

I would like to hand this branch over to @MrCirdo. I think I have done with this. After this is handed over, I have some comments on @MrCirdo 's code, things I suggest that can be written better.

}

if (pid <= 0) {
xAsprintf(error, "Unable to get the pid");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This pid <= 0 check can be moved to before the unw_create_addr_space call. That way we can save an allocation and deallocation in case when the PID is invalid.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, you're alright! Good Catch!

unw_word_t pc;

BacktraceFrameData* frame = BacktraceFrameData_new();
frame->index = index;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we really need this index field in the BacktraceFrameData structure? Since the vector object of BacktraceFrameData is likely sorted by index already, we can derive the indices when showing the backtrace data.
A technical advantage of leaving out this field is that a BacktraceFrameData can then initialize to all zeros. That saves code size.

Copy link
Contributor

Choose a reason for hiding this comment

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

Your argument makes sense. Sometimes, when unw_get_proc_name returns an error, what I was doing was to skip the frame. However, to keep the display coherent, this index was introduced. It can be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MrCirdo In case there is a failure in processing an entry in the list (such as a process name among a list of processes), a dummy entry can be added to indicate the error to keep the index numbering sane (when displayed).

if (unw_get_elf_filename(&cursor, elfFileName, sizeof(elfFileName), &offsetElfFileName) == 0) {
frame->objectPath = xStrndup(elfFileName, 2048);

char *lastSlash = strrchr(frame->objectPath, '/');
Copy link
Contributor Author

Choose a reason for hiding this comment

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

strrchr() can return NULL when the input string frame->objectPath contains no slashes.
This can cause the xStrndup(lastSlash + 1, 2048); to dereference an invalid pointer. We definitely need a null pointer check here.

(Thanks to the basename() API hell in libiberty that I discovered this one - an unsafe imitate of basename().)

Copy link
Contributor

Choose a reason for hiding this comment

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

Well See! I didn't catch this one! I'll fix it!

@Explorer09 Explorer09 changed the title Configure script changes for backtrace feature Backtrace screen (improvements over #1270) Nov 23, 2025
@MrCirdo
Copy link
Contributor

MrCirdo commented Nov 23, 2025

I think I have done with this.

Great! Perfect! Thank you very much!

After this is handed over, I have some comments on @MrCirdo 's code, things I suggest that can be written better.

With pleasure!

Wait, let’s get on the same page @Explorer09.
My idea was to split my PR into parts. The first part, which is presented here, involves adding a better configuration to my original PR. The second part is the behavior of the backtrace screen. And here you split both (Deeply apologize if I explain my idea very badly). If I understand well what @BenBE said, this PR would serve as a good base for #1270. So my question is : Do I have to close #1270 and continue my work on this one? I'm confused 😄

My primary concern about supporting the BSD platform (FreeBSD, NetBSD, macOS, etc) is that I don't know if ptrace(2) has the same behavior everywhere. (I suppose yes, but I've never used a BSD platform). So, reassure me, @Explorer09, that's the case?

NB : Sorry if I take time to answer because I need to do some preparation for a coding interview.

@Explorer09
Copy link
Contributor Author

Explorer09 commented Nov 23, 2025

My primary concern about supporting the BSD platform (FreeBSD, NetBSD, macOS, etc) is that I don't know if ptrace(2) has the same behavior everywhere. (I suppose yes, but I've never used a BSD platform). So, reassure me, @Explorer09, that's the case?

I didn't test running the code on BSD yet. The only thing I've tested is building htop with libunwind-ptrace and libiberty on FreeBSD on a CI server. I've read the man page of ptrace(2) for FreeBSD and got the equivalent keywords (PT_ATTACH and PT_DETACH), and those are what I've done.

My aim is to make it buildable in Linux and FreeBSD; other OSes are too difficult and I would expect libunwind port to those platforms first before we try making our backtrace feature work there.

@BenBE
Copy link
Member

BenBE commented Nov 24, 2025

I think I have done with this.

Great! Perfect! Thank you very much!

I.e. no further changes from @Explorer09 unless needed/requested. And possibly rebases onto main maybe.

After this is handed over, I have some comments on @MrCirdo 's code, things I suggest that can be written better.

With pleasure!

Wait, let’s get on the same page @Explorer09.
My idea was to split my PR into parts. The first part, which is presented here, involves adding a better configuration to my original PR. The second part is the behavior of the backtrace screen. And here you split both (Deeply apologize if I explain my idea very badly). If I understand well what @BenBE said, this PR would serve as a good base for #1270. So my question is : Do I have to close #1270 and continue my work on this one? I'm confused 😄

I think this PR will likely stay as is; i.e. no major changes.

My primary concern about supporting the BSD platform (FreeBSD, NetBSD, macOS, etc) is that I don't know if ptrace(2) has the same behavior everywhere. (I suppose yes, but I've never used a BSD platform). So, reassure me, @Explorer09, that's the case?

You can ask @fraggerfox regarding NetBSD details if necessary.

NB : Sorry if I take time to answer because I need to do some preparation for a coding interview.

NP.

@Explorer09
Copy link
Contributor Author

Explorer09 commented Nov 24, 2025

My primary concern about supporting the BSD platform (FreeBSD, NetBSD, macOS, etc) is that I don't know if ptrace(2) has the same behavior everywhere. (I suppose yes, but I've never used a BSD platform). So, reassure me, @Explorer09, that's the case?

You can ask @fraggerfox regarding NetBSD details if necessary.

The libunwind README says its supported operating systems are Linux, FreeBSD, Solaris, QNX and HP-UX (partially). NetBSD is not included.

For Solaris, there's no pre-built binary package for libunwind so testing on it would be difficult. QNX and HP-UX are out of htop's scope. So there remains Linux and FreeBSD, which are what I tried to make htop's backtrace work for.

@Explorer09 Explorer09 force-pushed the configure-enable-backtrace branch 3 times, most recently from f394979 to dd9cf40 Compare November 29, 2025 17:02
Explorer09 and others added 7 commits December 3, 2025 01:17
The configure option '--enable-unwind' doesn't actually enable a
feature in htop but selects a library dependency for a feature
(printing local backtrace for this case). Use a '--with-' naming
to reflect the option's purpose better.

For backward compatibility (with automated build scripts), using
'--enable-unwind' will still work but it will print a warning.

Signed-off-by: Kang-Che Sung <[email protected]>
Co-authored-by: Odric Roux-Paris <[email protected]>
Co-authored-by: Benny Baumann <[email protected]>
Signed-off-by: Kang-Che Sung <[email protected]>
Co-authored-by: Odric Roux-Paris <[email protected]>
Co-authored-by: Benny Baumann <[email protected]>
Signed-off-by: Kang-Che Sung <[email protected]>
Co-authored-by: Odric Roux-Paris <[email protected]>
Co-authored-by: Benny Baumann <[email protected]>
Signed-off-by: Kang-Che Sung <[email protected]>
For Linux and FreeBSD build jobs.
Signed-off-by: Kang-Che Sung <[email protected]>
Co-authored-by: Benny Baumann <[email protected]>
@Explorer09 Explorer09 force-pushed the configure-enable-backtrace branch from dd9cf40 to 86faa3d Compare December 2, 2025 17:20

char* buf;

while (!!(buf = malloc(allocSize))) {
Copy link
Contributor

@MrCirdo MrCirdo Dec 2, 2025

Choose a reason for hiding this comment

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

I would use realloc(3) here if the size is too small. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Using realloc is not helpful here because the buffer may be free'd for other reasons. realloc is best used on buffers with content you need to preserve, which is not the case here.

@MrCirdo
Copy link
Contributor

MrCirdo commented Dec 2, 2025

Wait, let’s get on the same page @Explorer09.
My idea was to split my PR into parts. The first part, which is presented here, involves adding a better configuration to my original PR. The second part is the behavior of the backtrace screen. And here you split both (Deeply apologize if I explain my idea very badly). If I understand well what @BenBE said, this PR would serve as a good base for #1270. So my question is : Do I have to close #1270 and continue my work on this one? I'm confused 😄

I think this PR will likely stay as is; i.e. no major changes.

Perfect! 😄 I closed the first one.

Can I push on your branch @Explorer09 to fix the problem you emphasized?

@Explorer09
Copy link
Contributor Author

Wait, let’s get on the same page @Explorer09.
My idea was to split my PR into parts. The first part, which is presented here, involves adding a better configuration to my original PR. The second part is the behavior of the backtrace screen. And here you split both (Deeply apologize if I explain my idea very badly). If I understand well what @BenBE said, this PR would serve as a good base for #1270. So my question is : Do I have to close #1270 and continue my work on this one? I'm confused 😄

I think this PR will likely stay as is; i.e. no major changes.

Perfect! 😄 I closed the first one.

Can I push on your branch @Explorer09 to fix the problem you emphasized?

I have enabled push access for this particular branch configure-enable-backtrace, so feel free to push.

#ifdef HAVE_DEMANGLING
char* Generic_Demangle(const char* mangled) {
# if defined(HAVE_LIBIBERTY_CPLUS_DEMANGLE)
int options = DMGL_PARAMS | DMGL_AUTO;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As mentioned in #1270, I would like to document the reasoning on the choice regarding the 6 boolean flags supported by cplus_demangle function:

DMGL_PARAMS, DMGL_ANSI, DMGL_VERBOSE, DMGL_TYPES, DMGL_RET_POSTFIX and DMGL_RET_DROP

For now I recognised why the use of DMGL_PARAMS here (necessary for C++ to distinguish function overloads), but haven't looked up on what the other 5 options do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build system 🔧 Affects the build system rather then the user experience code quality ♻️ Code quality enhancement enhancement Extension or improvement to existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants