Skip to content

[LLDB] added getName method in SBModule #150331

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

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

Conversation

barsolo2000
Copy link
Contributor

added getName method in SBModule.h and .cpp in order to get the name of the module from m_object_name.

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added the lldb label Jul 23, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 23, 2025

@llvm/pr-subscribers-lldb

Author: None (barsolo2000)

Changes

added getName method in SBModule.h and .cpp in order to get the name of the module from m_object_name.


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

2 Files Affected:

  • (modified) lldb/include/lldb/API/SBModule.h (+3)
  • (modified) lldb/source/API/SBModule.cpp (+8)
diff --git a/lldb/include/lldb/API/SBModule.h b/lldb/include/lldb/API/SBModule.h
index 85332066ee687..ed90c48849699 100644
--- a/lldb/include/lldb/API/SBModule.h
+++ b/lldb/include/lldb/API/SBModule.h
@@ -296,6 +296,9 @@ class LLDB_API SBModule {
   /// Remove any global modules which are no longer needed.
   static void GarbageCollectAllocatedModules();
 
+  /// Return the name of the module.
+  const char *GetName() const;
+
 private:
   friend class SBAddress;
   friend class SBFrame;
diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp
index 985107ec68efd..9eb0ae3cb3dba 100644
--- a/lldb/source/API/SBModule.cpp
+++ b/lldb/source/API/SBModule.cpp
@@ -671,3 +671,11 @@ void SBModule::GarbageCollectAllocatedModules() {
   const bool mandatory = false;
   ModuleList::RemoveOrphanSharedModules(mandatory);
 }
+
+const char *SBModule::GetName() const {
+  LLDB_INSTRUMENT_VA(this);
+  if (!m_opaque_sp) {
+    return nullptr;
+  }
+  return m_opaque_sp->GetObjectName().AsCString();
+}
\ No newline at end of file

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

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

TL;DR:

const char *SBModule::GetName() const {
  LLDB_INSTRUMENT_VA(this);

  if (!m_opaque_sp) 
    return nullptr;

  return m_opaque_sp->GetObjectName().AsCString();
}

This also needs a test.

Comment on lines 677 to 679
if (!m_opaque_sp) {
return nullptr;
}
Copy link
Member

Choose a reason for hiding this comment

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

No braces around single-line ifs.

Suggested change
if (!m_opaque_sp) {
return nullptr;
}
if (!m_opaque_sp)
return nullptr;

if (!m_opaque_sp) {
return nullptr;
}
auto mod_name = m_opaque_sp->GetObjectName();
Copy link
Member

Choose a reason for hiding this comment

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

Don't use auto if the type isn't obvious from the right hand side.

Suggested change
auto mod_name = m_opaque_sp->GetObjectName();
ConstString mod_name = m_opaque_sp->GetObjectName();

Comment on lines 681 to 684
if (!mod_name) {
return nullptr;
}
return mod_name.AsCString();
Copy link
Member

Choose a reason for hiding this comment

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

AsCString will return nullptr if the ConstString is empty, so the previous check is redundant.

@@ -671,3 +671,15 @@ void SBModule::GarbageCollectAllocatedModules() {
const bool mandatory = false;
ModuleList::RemoveOrphanSharedModules(mandatory);
}

const char *SBModule::GetName() const {
LLDB_INSTRUMENT_VA(this);
Copy link
Member

Choose a reason for hiding this comment

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

There should be a newline after LLDB_INSTRUMENT_VA

Suggested change
LLDB_INSTRUMENT_VA(this);
LLDB_INSTRUMENT_VA(this);

return nullptr;
}
return mod_name.AsCString();
}
Copy link
Member

Choose a reason for hiding this comment

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

Missing newline.

@Jlalond
Copy link
Contributor

Jlalond commented Jul 24, 2025

This also needs a test.

@JDevlieghere I'm working with Bar on this, one expected issue we're experiencing is almost every module has a null name. Even trying on Darwin if we loop over all the modules all the names are none.

The original rationale behind this patch was there are sometimes modules without a UUID, and I wanted to log the name of these modules, especially given Module itself exposes a name. However it appears my hypothesis was wrong, any idea or context why that is?

CC: @clayborg

@jimingham
Copy link
Collaborator

This also needs a test.

@JDevlieghere I'm working with Bar on this, one expected issue we're experiencing is almost every module has a null name. Even trying on Darwin if we loop over all the modules all the names are none.

The original rationale behind this patch was there are sometimes modules without a UUID, and I wanted to log the name of these modules, especially given Module itself exposes a name. However it appears my hypothesis was wrong, any idea or context why that is?

CC: @clayborg

That name is actually derived from the ObjectFile, not from the module. In some of the Module constructors we don't make the ObjectFile at construction time, but wait till someone calls Module::GetObjectFile. But from what I can see GetObjectFile doesn't actually set m_object_name. That's probably what you are seeing.

But also, if you are on the lazy code path, you might be in a state where we haven't made the object file yet - in which case we haven't set m_object_name. So your GetName probably has to call GetObjectFile first - that will be a no-op if the ObjectFile has been made - and then access m_object_name.

@labath
Copy link
Collaborator

labath commented Jul 25, 2025

I don't think that m_object_name is what you're looking for. It's supposed to be used for disambiguation when a single physical file contains multiple logical object files, such as with BSD archives. It being empty for "normal" files is kind of expected:

  ConstString m_object_name; ///< The name an object within this module that is
                             /// selected, or empty of the module is represented
                             /// by \a m_file.

Though I guess that brings up the question of what is the expected result of GetName for files within BSD archives...


if (!m_opaque_sp)
return nullptr;
m_opaque_sp->GetObjectFile();
Copy link
Member

Choose a reason for hiding this comment

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

This feels like a code smell. GetObjectName should probably fill in the object file for you instead of manually needing to call this before GetObjectName.

Comment on lines 37 to 39
#If no valid file, expect GetName() to be a non - empty string
self.assertIsInstance(name, str)
self.assertTrue(name, "Expected a non-empty name for module without a valid file")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why should that be true? I think we need to start by defining what exactly do you expect this function to return.

Copy link
Contributor

Choose a reason for hiding this comment

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

@labath

I think the best case for this API would be returning a valid string identifier when there is no backing file. VDSO is the example I have in mind but a module jitted in memory only could also make sense.

Per the code you linked

  ConstString m_object_name; ///< The name an object within this module that is
                                                    /// selected, or empty of the module is represented
                                                    /// by \a m_file.

Shouldn't this be the case? I'm very open to how we implement this but my goals align with the comments, which is obtaining a valid identifier when I can't fall back to the file for identification

Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be the case?

I don't think so. This fields is really meant for the case where a single file represents multiple logical modules (in which case it disambiguates them), as is the case with BSD archives. See ObjectContainerBSDArchive::GetObjectFile to see how it's used.

In the case of vdso, the "name" ends up in the Module::m_file field, if I'm following the code in DynamicLoaderPOSIXDYLD::LoadVDSO correctly. The same thing happens with the JIT modules (JITLoaderGDB::ReadJITDescriptorImpl). Now, you could argue that's not the right place to put this information, and that it should go somehwere else... However, I don't think m_object_name is that place.

BTW, if you're looking for a truly unique identifier (and not just a name), you may want to look at #148877, which adds an integer ID for that purpose. I think it would be okay to expose that through the SB API if there's a use case for it.

What do you intend to use this for? Just show it to the user, or use in some sort of a critical capacity?

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the great context on this Pavel

What do you intend to use this for? Just show it to the user, or use in some sort of a critical capacity?

I'm currently trying to generate some metrics around Modules, and there are some cases where I don't have access to the UUID. I think the identifier would be great, but a generic name field would also be nice for logging.

Should we pivot this change to expose the m_file name if m_object_name is not present? If I follow correct the precedence of 'uniqueness' is

  • UUID
  • The numerical ID you linked
  • Object name
  • File name

Having a 'helper' accessor exposing the object name or the file name would solve my needs.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If I follow correct the precedence of 'uniqueness' is

I don't think you can really order these, as they all have different properties. The UUID (build-id) is assigned at build time, and it's supposed to be unique -- but it may not be assigned, and you can't really guarantee its uniqueness, which makes it unsuitable for some uses. The numeric ID uniquely identifies a loaded copy of a specific module, but it's a purely internal thing, so you can't use it to link two sessions together. The object name is only meaningful within an archive (you can have two archives with the same object), so it's best to think of these two as a single entity -- the file+object name pair uniquely identifies an object file on a specific file system at a specific point in time.

Having a 'helper' accessor exposing the object name or the file name would solve my needs.

The file name is available already through GetFileSpec and it shows the vdso "name":

(lldb) script for m in lldb.target.modules: print(m.GetFileSpec())
/bin/ls
/lib64/ld-linux-x86-64.so.2
[vdso]

Is that enough? If you want to also access the object name, I think the simplest approach would be to expose m_object_name via Get*Object*Name() as that makes it clear what it's doing and it matches the function name of SBModuleSpec. Then you can combine these however you see fit on your end.

Copy link
Collaborator

@labath labath left a comment

Choose a reason for hiding this comment

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

The code looks good, but I have a problem with the docstring, as it captures none of the subtlety around this function (which was discussed in the other thread).

I'd recommend something like:
"If this Module represents a part of a larger file, returns the name of that part. Otherwise, returns nullptr."

The test is also pretty weak. Basically, all it does is verify that the result is a string. I'd suggest looking at TestBSDArchives.py. I think it should be fairly easy to extend that to cover this function as well -- just take one of the SBModuleSpecs floating around and use that to create SBModule (then call this function).

Copy link

github-actions bot commented Aug 4, 2025

✅ With the latest revision this PR passed the Python code formatter.

Copy link

github-actions bot commented Aug 4, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Summary:

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:
Copy link
Collaborator

@labath labath left a comment

Choose a reason for hiding this comment

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

Looks good, with a couple of adjustments to the test. You can construct a SBModule without adding it to a target. Adding the .o file to the target is unnecessary, and somewhat strange.

Comment on lines 47 to 48
#create a module from the arhive using the sepc
module = target.AddModule(spec)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
#create a module from the arhive using the sepc
module = target.AddModule(spec)
module = lldb.SBModule(spec)

Comment on lines 38 to 39
target = self.dbg.CreateTarget(None)
self.assertTrue(target.IsValid(), "Target is valid")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
target = self.dbg.CreateTarget(None)
self.assertTrue(target.IsValid(), "Target is valid")

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.

7 participants