Skip to content

[lldb] Improve error message for unrecognized executables #97490

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

Merged
merged 1 commit into from
Jul 8, 2024

Conversation

JDevlieghere
Copy link
Member

Currently, LLDB prints out a rather unhelpful error message when passed a file that it doesn't recognize as an executable.

error: '/path/to/file' doesn't contain any 'host' platform
architectures: arm64, armv7, armv7f, armv7k, armv7s, armv7m, armv7em,
armv6m, armv6, armv5, armv4, arm, thumbv7, thumbv7k, thumbv7s,
thumbv7f, thumbv7m, thumbv7em, thumbv6m, thumbv6, thumbv5, thumbv4t,
thumb, x86_64, x86_64, arm64, arm64e

I did a quick search internally and found at least 24 instances of users being confused by this. This patch improves the error message when it doesn't recognize the file as an executable, but keeps the existing error message otherwise, i.e. when it's an object file we understand, but the current platform doesn't support.

Currently, LLDB prints out a rather unhelpful error message when passed
a file that it doesn't recognize as an executable.

  error: '/path/to/file' doesn't contain any 'host' platform
  architectures: arm64, armv7, armv7f, armv7k, armv7s, armv7m, armv7em,
  armv6m, armv6, armv5, armv4, arm, thumbv7, thumbv7k, thumbv7s,
  thumbv7f, thumbv7m, thumbv7em, thumbv6m, thumbv6, thumbv5, thumbv4t,
  thumb, x86_64, x86_64, arm64, arm64e, arm64, arm64e

I did a quick search internally and found at least 24 instances of users
being confused by this. This patch improves the error message when it
doesn't recognize the file as an executable, but keeps the existing
error message otherwise, i.e. when it's an object file we understand,
but the current platform doesn't support.
@llvmbot
Copy link
Member

llvmbot commented Jul 2, 2024

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

Changes

Currently, LLDB prints out a rather unhelpful error message when passed a file that it doesn't recognize as an executable.

> error: '/path/to/file' doesn't contain any 'host' platform
> architectures: arm64, armv7, armv7f, armv7k, armv7s, armv7m, armv7em,
> armv6m, armv6, armv5, armv4, arm, thumbv7, thumbv7k, thumbv7s,
> thumbv7f, thumbv7m, thumbv7em, thumbv6m, thumbv6, thumbv5, thumbv4t,
> thumb, x86_64, x86_64, arm64, arm64e

I did a quick search internally and found at least 24 instances of users being confused by this. This patch improves the error message when it doesn't recognize the file as an executable, but keeps the existing error message otherwise, i.e. when it's an object file we understand, but the current platform doesn't support.


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

4 Files Affected:

  • (modified) lldb/include/lldb/Symbol/ObjectFile.h (+1)
  • (modified) lldb/source/Symbol/ObjectFile.cpp (+9)
  • (modified) lldb/source/Target/Platform.cpp (+44-43)
  • (modified) lldb/test/Shell/ObjectFile/PECOFF/invalid-export-table.yaml (+1-1)
diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h
index 6348d8103f85d..8592323322e38 100644
--- a/lldb/include/lldb/Symbol/ObjectFile.h
+++ b/lldb/include/lldb/Symbol/ObjectFile.h
@@ -178,6 +178,7 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
                                         lldb::offset_t file_offset,
                                         lldb::offset_t file_size,
                                         lldb_private::ModuleSpecList &specs);
+  static bool IsObjectFile(lldb_private::FileSpec file_spec);
   /// Split a path into a file path with object name.
   ///
   /// For paths like "/tmp/foo.a(bar.o)" we often need to split a path up into
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
index d890ad92e8312..2608a9c5fb79a 100644
--- a/lldb/source/Symbol/ObjectFile.cpp
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -184,6 +184,15 @@ ObjectFileSP ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp,
   return object_file_sp;
 }
 
+bool ObjectFile::IsObjectFile(lldb_private::FileSpec file_spec) {
+  DataBufferSP data_sp;
+  offset_t data_offset = 0;
+  ModuleSP module_sp = std::make_shared<Module>(file_spec);
+  return static_cast<bool>(ObjectFile::FindPlugin(
+      module_sp, &file_spec, 0, FileSystem::Instance().GetByteSize(file_spec),
+      data_sp, data_offset));
+}
+
 size_t ObjectFile::GetModuleSpecifications(const FileSpec &file,
                                            lldb::offset_t file_offset,
                                            lldb::offset_t file_size,
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index b3116545b91d1..d57f644be5611 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -766,7 +766,6 @@ Status
 Platform::ResolveExecutable(const ModuleSpec &module_spec,
                             lldb::ModuleSP &exe_module_sp,
                             const FileSpecList *module_search_paths_ptr) {
-  Status error;
 
   // We may connect to a process and use the provided executable (Don't use
   // local $PATH).
@@ -775,55 +774,57 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec,
   // Resolve any executable within a bundle on MacOSX
   Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
 
-  if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) ||
-      module_spec.GetUUID().IsValid()) {
-    if (resolved_module_spec.GetArchitecture().IsValid() ||
-        resolved_module_spec.GetUUID().IsValid()) {
-      error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
-                                          module_search_paths_ptr, nullptr,
-                                          nullptr);
+  if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) &&
+      !module_spec.GetUUID().IsValid())
+    return Status::createWithFormat("'{0}' does not exist",
+                                    resolved_module_spec.GetFileSpec());
+
+  if (resolved_module_spec.GetArchitecture().IsValid() ||
+      resolved_module_spec.GetUUID().IsValid()) {
+    Status error =
+        ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
+                                    module_search_paths_ptr, nullptr, nullptr);
 
+    if (exe_module_sp && exe_module_sp->GetObjectFile())
+      return error;
+    exe_module_sp.reset();
+  }
+  // No valid architecture was specified or the exact arch wasn't found.
+  // Ask the platform for the architectures that we should be using (in the
+  // correct order) and see if we can find a match that way.
+  StreamString arch_names;
+  llvm::ListSeparator LS;
+  ArchSpec process_host_arch;
+  Status error;
+  for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) {
+    resolved_module_spec.GetArchitecture() = arch;
+    error =
+        ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
+                                    module_search_paths_ptr, nullptr, nullptr);
+    if (error.Success()) {
       if (exe_module_sp && exe_module_sp->GetObjectFile())
-        return error;
-      exe_module_sp.reset();
+        break;
+      error.SetErrorToGenericError();
     }
-    // No valid architecture was specified or the exact arch wasn't found.
-    // Ask the platform for the architectures that we should be using (in the
-    // correct order) and see if we can find a match that way.
-    StreamString arch_names;
-    llvm::ListSeparator LS;
-    ArchSpec process_host_arch;
-    for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) {
-      resolved_module_spec.GetArchitecture() = arch;
-      error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
-                                          module_search_paths_ptr, nullptr,
-                                          nullptr);
-      if (error.Success()) {
-        if (exe_module_sp && exe_module_sp->GetObjectFile())
-          break;
-        error.SetErrorToGenericError();
-      }
 
-      arch_names << LS << arch.GetArchitectureName();
-    }
+    arch_names << LS << arch.GetArchitectureName();
+  }
 
-    if (error.Fail() || !exe_module_sp) {
-      if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) {
-        error.SetErrorStringWithFormatv(
-            "'{0}' doesn't contain any '{1}' platform architectures: {2}",
-            resolved_module_spec.GetFileSpec(), GetPluginName(),
-            arch_names.GetData());
-      } else {
-        error.SetErrorStringWithFormatv("'{0}' is not readable",
-                                        resolved_module_spec.GetFileSpec());
-      }
-    }
-  } else {
-    error.SetErrorStringWithFormatv("'{0}' does not exist",
+  if (exe_module_sp && error.Success())
+    return {};
+
+  if (!FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec()))
+    return Status::createWithFormat("'{0}' is not readable",
                                     resolved_module_spec.GetFileSpec());
-  }
 
-  return error;
+  if (!ObjectFile::IsObjectFile(resolved_module_spec.GetFileSpec()))
+    return Status::createWithFormat("'{0}' is not a valid executable",
+                                    resolved_module_spec.GetFileSpec());
+
+  return Status::createWithFormat(
+      "'{0}' doesn't contain any '{1}' platform architectures: {2}",
+      resolved_module_spec.GetFileSpec(), GetPluginName(),
+      arch_names.GetData());
 }
 
 Status Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec,
diff --git a/lldb/test/Shell/ObjectFile/PECOFF/invalid-export-table.yaml b/lldb/test/Shell/ObjectFile/PECOFF/invalid-export-table.yaml
index 389261ad9b10a..e6564661b96fd 100644
--- a/lldb/test/Shell/ObjectFile/PECOFF/invalid-export-table.yaml
+++ b/lldb/test/Shell/ObjectFile/PECOFF/invalid-export-table.yaml
@@ -4,7 +4,7 @@
 # RUN: yaml2obj %s -o %t.exe
 # RUN: %lldb %t.exe 2>&1 | FileCheck %s
 
-# CHECK: error: '{{.*}}' doesn't contain any {{.*}} platform architectures
+# CHECK: error: '{{.*}}' is not a valid executable
 --- !COFF
 OptionalHeader:
   AddressOfEntryPoint: 4096

Copy link
Collaborator

@jasonmolenda jasonmolenda left a comment

Choose a reason for hiding this comment

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

This look good. I like distinguishing between "is not a known binary type" and "does not contain an architecture supported on this platform (but is a binary file that we recognize)".

@JDevlieghere JDevlieghere merged commit ed7e468 into llvm:main Jul 8, 2024
8 checks passed
@JDevlieghere JDevlieghere deleted the unrecognized-exe-error branch July 8, 2024 16:29
splhack added a commit to splhack/llvm-project that referenced this pull request Jul 12, 2024
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.

4 participants