Skip to content

Conversation

aokblast
Copy link
Contributor

Currently, LLDB in FreeBSD host sets the Process Architecture used by lldbserver as Default one. Which cause problem when trying to debug a 32bit binary on amd64 platform since the lldb itself will found mismatch architecture with lldbserver's return.

Notice that this patch is only a partial fix for the debugging problem. We are still unable to debug x86 on x86_64 so that we don't provide testcase in this patch.

See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289945

Currently, LLDB in FreeBSD host sets the Process Architecture used by
lldbserver as Default one. Which cause problem when trying to debug a
32bit binary on amd64 platform since the lldb itself will found mismatch
architecture with lldbserver's return.

Notice that this patch is only a partial fix for the debugging problem.
We are still unable to debug x86 on x86_64 so that we don't provide
testcase in this patch.
@llvmbot
Copy link
Member

llvmbot commented Oct 10, 2025

@llvm/pr-subscribers-lldb

Author: None (aokblast)

Changes

Currently, LLDB in FreeBSD host sets the Process Architecture used by lldbserver as Default one. Which cause problem when trying to debug a 32bit binary on amd64 platform since the lldb itself will found mismatch architecture with lldbserver's return.

Notice that this patch is only a partial fix for the debugging problem. We are still unable to debug x86 on x86_64 so that we don't provide testcase in this patch.

See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289945


Full diff: https://github.com/llvm/llvm-project/pull/162811.diff

1 Files Affected:

  • (modified) lldb/source/Host/freebsd/Host.cpp (+28-13)
diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp
index 14c0e9f2209d2..fa7efad466bad 100644
--- a/lldb/source/Host/freebsd/Host.cpp
+++ b/lldb/source/Host/freebsd/Host.cpp
@@ -14,12 +14,13 @@
 #include <sys/sysctl.h>
 #include <sys/user.h>
 
-#include <machine/elf.h>
-
 #include <cstdio>
 #include <dlfcn.h>
 #include <execinfo.h>
 
+#include "llvm/Object/ELF.h"
+
+#include "lldb/Host/FileSystem.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Utility/DataBufferHeap.h"
@@ -97,17 +98,33 @@ GetFreeBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
     proc_args.AppendArgument(llvm::StringRef(cstr));
   }
 
-  return true;
-}
-
-static bool GetFreeBSDProcessCPUType(ProcessInstanceInfo &process_info) {
-  if (process_info.ProcessIDIsValid()) {
-    process_info.GetArchitecture() =
-        HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+  auto buffer_sp = FileSystem::Instance().CreateDataBuffer(pathname, 0x20, 0);
+  if (!buffer_sp) {
+    process_info.Clear();
     return true;
   }
-  process_info.GetArchitecture().Clear();
-  return false;
+  uint8_t exe_class =
+      llvm::object::getElfArchType(
+          {reinterpret_cast<const char *>(buffer_sp->GetBytes()),
+           size_t(buffer_sp->GetByteSize())})
+          .first;
+
+  switch (exe_class) {
+  case llvm::ELF::ELFCLASS32:
+    process_info.SetArchitecture(
+        HostInfo::GetArchitecture(HostInfo::eArchKind32));
+    break;
+  case llvm::ELF::ELFCLASS64:
+    process_info.SetArchitecture(
+        HostInfo::GetArchitecture(HostInfo::eArchKind64));
+    break;
+  case llvm::ELF::ELFCLASSNONE:
+    process_info.SetArchitecture(
+        HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
+    break;
+  }
+
+  return true;
 }
 
 static bool GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
@@ -214,7 +231,6 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
     // Make sure our info matches before we go fetch the name and cpu type
     if (match_info_noname.Matches(process_info) &&
         GetFreeBSDProcessArgs(&match_info, process_info)) {
-      GetFreeBSDProcessCPUType(process_info);
       if (match_info.Matches(process_info))
         process_infos.push_back(process_info);
     }
@@ -228,7 +244,6 @@ bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
 
   if (GetFreeBSDProcessArgs(NULL, process_info)) {
     // should use libprocstat instead of going right into sysctl?
-    GetFreeBSDProcessCPUType(process_info);
     GetFreeBSDProcessUserAndGroup(process_info);
     return true;
   }

@aokblast
Copy link
Contributor Author

I don't provide test case since it still failed on debugging x32 from x86_64 platform when receiving signal. However, it stop breaking when loading binary.

Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

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

LGTM, I see that NetBSD and Linux do this too.

Though I doubt whether debugging works on those platforms either, and I don't think we have upstream tests for it so I won't demand them here.

This change applies to AArch64 as well, right? At least the code is generic, maybe AArch32 binaries aren't allowed on AArch64 FreeBSD.

If you do get this working overall, I would like to see tests that run on Linux. If it's not a massive amount of work I can help fix Linux, if it is though, FreeBSD only test case would be fine. I'll take something over nothing.

@aokblast
Copy link
Contributor Author

aokblast commented Oct 10, 2025

LGTM, I see that NetBSD and Linux do this too.

Though I doubt whether debugging works on those platforms either, and I don't think we have upstream tests for it so I won't demand them here.

This change applies to AArch64 as well, right? At least the code is generic, maybe AArch32 binaries aren't allowed on AArch64 FreeBSD.

This is an interesting question. I think that there are already some aarch64 based chip, like this, does not support running arm32 naturally.
I have tried compiling -m32 on our aarch64 based server. And the error shows:
ld: error: /tmp/main-2d8f5f.o is incompatible with /usr/lib/crt1.o
cc: error: linker command failed with exit code 1 (use -v to see invocation).
I suspect that we might see similar error on our rtld since we don't ship 32bit sysroots.
Due to these reasons, I would suggest that LLDB should not do any assuption and just run the binary to see if run time support it.

If you do get this working overall, I would like to see tests that run on Linux. If it's not a massive amount of work I can help fix Linux, if it is though, FreeBSD only test case would be fine. I'll take something over nothing.

Ok! I plan to provide at least FreeBSD test cases. I would try my best to provide the Linux one if I can get a one shot. Since I don't have any powerful Linux machine for debugging.

@DavidSpickett
Copy link
Collaborator

Makes sense, if x86 is your use case, no need to pursue anything else.

Now I remember someone did submit fixes for Arm32 on Arm64 Linux debugging. So it may be working there already.

I would try my best to provide the Linux one if I can get a one shot. Since I don't have any powerful Linux machine for debugging.

Linux is my usual host so just aim for a FreeBSD test and I'll adapt it later.

I did briefly consider running the entire test suite on Arm64 but with all debugees as 32-bit. Then I realised how many assumptions are made in various places and decided against it.

So a basic test that exercises the main debug APIs would be fine. Run to a breakpoint, read some memory, print a pointer. Anything that comes to mind that might be related to bit-ness.

@DavidSpickett
Copy link
Collaborator

I can merge this if you need me to.

@aokblast
Copy link
Contributor Author

I can merge this if you need me to.

Sure. Thanks for your help!

@DavidSpickett DavidSpickett merged commit 394e7de into llvm:main Oct 10, 2025
12 checks passed
@DavidSpickett
Copy link
Collaborator

This is an interesting question. I think that there are already some aarch64 based chip, like this, does not support running arm32 naturally.

The userspace part of this is called FEAT_AA32EL0 and yes, it's been optional for a long time and becoming more common for it to not be present.

@aokblast
Copy link
Contributor Author

FEAT_AA32EL0

Wow. thanks for your link! I am curious that do arm guys treat these models specially? Like have special ubuntu release without 32bit sysroots? I don't discover any FEAT_AA32EL0 string in LLVM so it might not be toolchain to have special arch triple to support it. Or arm just run it normally and let the kernel trap when running 32bit code.

@DavidSpickett
Copy link
Collaborator

Like have special ubuntu release without 32bit sysroots?

To be honest I've never tried it. I believe the Android NDK ships with toolchains to do this though. On any debian system I'd expect to be able to install a cross-compiler for it (https://wiki.debian.org/Multiarch/HOWTO). I know I can for example install SystemZ tools on Arm Ubuntu. Arm also provides Linux GCC toolchains you can download separately.

You wouldn't see this feature name in in the toolchain. Even if you ran Ubuntu on one of these AArch32-less systems, I bet you can install the 32-bit toolchains still, as the package manager doesn't look that deeply. You'd find out when you get some probably strange error from the system or dynamic linker.

I don't think it's a very popular thing to do generally. Valuable for some I'm sure, but not something I have come across many times.

And I don't think you asked this but for completeness, were we not able to get hold of a machine with or without this feature, Arm's Fixed Virtual Platforms (FVP) can be configured to emulate it. Possibly QEMU too, but it does not cover absolutely everything like FVP does (not a criticism, each one has its own goals).

@DavidSpickett
Copy link
Collaborator

My impression is that 32-bit executables are much more common on x86. To the point where there are standard flags like -m32, which we do not have for AArch64/AArch32.

#include <cstdio>
#include <dlfcn.h>
#include <execinfo.h>

#include "llvm/Object/ELF.h"
Copy link
Member

Choose a reason for hiding this comment

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

Please group this together with the llvm header below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I totally fix the issue for i386 on x86_64 platform. Also includes this suggestion. Thanks!

#162890

@emaste
Copy link
Member

emaste commented Oct 10, 2025

@aokblast for reference we build 32-bit FreeBSD arm packages in a 32-bit jail on an arm64 host, on Ampere eMAG systems.

@aokblast
Copy link
Contributor Author

Like have special ubuntu release without 32bit sysroots?

To be honest I've never tried it. I believe the Android NDK ships with toolchains to do this though. On any debian system I'd expect to be able to install a cross-compiler for it (https://wiki.debian.org/Multiarch/HOWTO). I know I can for example install SystemZ tools on Arm Ubuntu. Arm also provides Linux GCC toolchains you can download separately.

You wouldn't see this feature name in in the toolchain. Even if you ran Ubuntu on one of these AArch32-less systems, I bet you can install the 32-bit toolchains still, as the package manager doesn't look that deeply. You'd find out when you get some probably strange error from the system or dynamic linker.

I don't think it's a very popular thing to do generally. Valuable for some I'm sure, but not something I have come across many times.

And I don't think you asked this but for completeness, were we not able to get hold of a machine with or without this feature, Arm's Fixed Virtual Platforms (FVP) can be configured to emulate it. Possibly QEMU too, but it does not cover absolutely everything like FVP does (not a criticism, each one has its own goals).

Thanks for your information! I am just curious on how arm handle these multiarch stuff.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants