Skip to content

Conversation

sedymrak
Copy link
Contributor

@sedymrak sedymrak commented Oct 7, 2025

When we take the following C program:

int main() {
  return 0;
}

and create a statically-linked executable from it:

clang -static -g -o main main.c

Then we can observe the following lldb behavior:

$ lldb
(lldb) target create main
Current executable set to '.../main' (x86_64).
(lldb) breakpoint set --name main
Breakpoint 1: where = main`main + 11 at main.c:2:3, address = 0x000000000022aa7b
(lldb) process launch
Process 3773637 launched: '/home/me/tmp/built-in/main' (x86_64)
Process 3773637 stopped
* thread #1, name = 'main', stop reason = breakpoint 1.1
    frame #0: 0x000000000022aa7b main`main at main.c:2:3
   1   	int main() {
-> 2   	  return 0;
   3   	}
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__int128").size
0
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("unsigned __int128").size
0
(lldb) quit

The value return by the SBTarget::FindFirstType method is wrong for the __int128 and unsigned __int128 basic types.

The proposed changes make the TypeSystemClang::GetBasicTypeEnumeration method consistent with gcc and clang C language extension related to 128-bit integer types as well as with the BuiltinType::getName method in the LLVM codebase itself.

When the above change is applied, the behavior of the lldb changes in the following (desired) way:

$ lldb
(lldb) target create main
Current executable set to '.../main' (x86_64).
(lldb) breakpoint set --name main
Breakpoint 1: where = main`main + 11 at main.c:2:3, address = 0x000000000022aa7b
(lldb) process launch
Process 3773637 launched: '/home/me/tmp/built-in/main' (x86_64)
Process 3773637 stopped
* thread #1, name = 'main', stop reason = breakpoint 1.1
    frame #0: 0x000000000022aa7b main`main at main.c:2:3
   1   	int main() {
-> 2   	  return 0;
   3   	}
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__int128").size
16
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("unsigned __int128").size
16
(lldb) quit

@sedymrak sedymrak requested a review from JDevlieghere as a code owner October 7, 2025 12:53
@sedymrak sedymrak force-pushed the fix-TypeSystemClang-GetBasicTypeEnumeration-method branch from 031ed28 to 3d32637 Compare October 7, 2025 14:47
@llvmbot llvmbot added the lldb label Oct 7, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 7, 2025

@llvm/pr-subscribers-lldb

Author: Matej Košík (sedymrak)

Changes

When we take the following C program:

int main() {
  return 0;
}

and create a statically-linked executable from it:

clang -static -g -o main main.c

Then we can observe the following lldb behavior:

$ lldb
(lldb) target create main
Current executable set to '.../main' (x86_64).
(lldb) breakpoint set --name main
Breakpoint 1: where = main`main + 11 at main.c:2:3, address = 0x000000000022aa7b
(lldb) process launch
Process 3773637 launched: '/home/me/tmp/built-in/main' (x86_64)
Process 3773637 stopped
* thread #<!-- -->1, name = 'main', stop reason = breakpoint 1.1
    frame #<!-- -->0: 0x000000000022aa7b main`main at main.c:2:3
   1   	int main() {
-&gt; 2   	  return 0;
   3   	}
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__int128").size
0
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("unsigned __int128").size
0
(lldb) quit

The value return by the SBTarget::FindFirstType method is wrong for the __int128 and unsigned __int128 basic types.

The proposed changes make the TypeSystemClang::GetBasicTypeEnumeration method consistent with gcc and clang C language extension related to 128-bit integer types as well as with the BuiltinType::getName method in the LLVM codebase itself.

When the above change is applied, the behavior of the lldb changes in the following (desired) way:

$ lldb
(lldb) target create main
Current executable set to '.../main' (x86_64).
(lldb) breakpoint set --name main
Breakpoint 1: where = main`main + 11 at main.c:2:3, address = 0x000000000022aa7b
(lldb) process launch
Process 3773637 launched: '/home/me/tmp/built-in/main' (x86_64)
Process 3773637 stopped
* thread #<!-- -->1, name = 'main', stop reason = breakpoint 1.1
    frame #<!-- -->0: 0x000000000022aa7b main`main at main.c:2:3
   1   	int main() {
-&gt; 2   	  return 0;
   3   	}
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__int128").size
16
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("unsigned __int128").size
16
(lldb) quit

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

2 Files Affected:

  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+2-2)
  • (modified) lldb/unittests/Symbol/TestTypeSystemClang.cpp (+2-2)
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 21c265ede0bc5..1a574c97d9e46 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -849,8 +849,8 @@ lldb::BasicType TypeSystemClang::GetBasicTypeEnumeration(llvm::StringRef name) {
       {"unsigned long long int", eBasicTypeUnsignedLongLong},
 
       // "int128"
-      {"__int128_t", eBasicTypeInt128},
-      {"__uint128_t", eBasicTypeUnsignedInt128},
+      {"__int128", eBasicTypeInt128},
+      {"unsigned __int128", eBasicTypeUnsignedInt128},
 
       // "bool"
       {"bool", eBasicTypeBool},
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index f673cceae00dd..df507739d5c73 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -159,9 +159,9 @@ TEST_F(TestTypeSystemClang, TestGetBasicTypeFromName) {
             GetBasicQualType("unsigned long long"));
   EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong),
             GetBasicQualType("unsigned long long int"));
-  EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128_t"));
+  EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128"));
   EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128),
-            GetBasicQualType("__uint128_t"));
+            GetBasicQualType("unsigned __uint128"));
   EXPECT_EQ(GetBasicQualType(eBasicTypeVoid), GetBasicQualType("void"));
   EXPECT_EQ(GetBasicQualType(eBasicTypeBool), GetBasicQualType("bool"));
   EXPECT_EQ(GetBasicQualType(eBasicTypeFloat), GetBasicQualType("float"));

EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128"));
EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128),
GetBasicQualType("__uint128_t"));
GetBasicQualType("unsigned __uint128"));
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
GetBasicQualType("unsigned __uint128"));
GetBasicQualType("unsigned __int128"));

Hence the PR CI test failure

@Michael137
Copy link
Member

So IIUC, the issue is that SBModule::FindFirstType falls back to TypeSystemClang::GetBuiltinTypeByName. Since __int128 and unsigned __int128 are the de-facto names for the builtin types, we expect LLDB to find them. But LLDB registers the 128-bit integer builtins as being called __int128_t and __uint128_t.

Seems like this dates back quite a while:

commit b43165b7a5d59d8178dc803ec0351d3a62a38946
Author: Greg Clayton <gclayton@apple.com>
Date:   Wed Dec 5 21:24:42 2012 +0000

    <rdar://problem/12749733>
    
    Always allows getting builtin types by name even if there is no backing debug information.
    
    llvm-svn: 169424

And there weren't associated tests for it, so hard to say why __int128_t was chosen. IIUC, __int128_t is a typedef to __int128. So using it for the name of the basic type seems wrong.

(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__int128").size
16
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("unsigned __int128").size
16

Could you add a test for this?

E.g., you could add this to lldb/test/API/functionalities/type_find_first/TestFindFirstType.py or lldb/test/API/python_api/sbtype_basic_type/TestSBTypeBasicType.py

On the flip-side it looks like the following commands do currently work today:

(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__int128_t").size
16
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__uint128_t").size
16

Do they still work after your patch?

@sedymrak sedymrak force-pushed the fix-TypeSystemClang-GetBasicTypeEnumeration-method branch from 3d32637 to 04fea01 Compare October 9, 2025 09:23
@sedymrak
Copy link
Contributor Author

sedymrak commented Oct 9, 2025

Concerning this (particular) question:

On the flip-side it looks like the following commands do currently work today:

(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__int128_t").size
16
(lldb) script lldb.debugger.GetSelectedTarget().FindFirstType("__uint128_t").size
16

Do they still work after your patch?

Since neither __int128_t nor __uint128_t are basic types, LLDB will return 0 by default.
However, if the program contains the definition of the __int128_t or __uint128_t type, then it will return 16 for that type. According to what I can see, in my branch:

  • whenever I use __int128_t or __uint128_t in my program, LLDB returns 16 for that type.
  • if I don't use __int128_t or __uint128_t in my program, LLDB returns 0 for these type (as it would return for any other random type-name that does not correspond to any of the defined types).

The behavior of LLDB will thus change in this respect, but the new behavior is the one that we expect
(as far as I understand it).

Copy link
Collaborator

@clayborg clayborg left a comment

Choose a reason for hiding this comment

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

This looks ok, but I think we should leave the old typename mappings in to make sure we don't break anyone's scripts that might be using the __int128_t or __uint128_t

Comment on lines 851 to 854
// "int128"
{"__int128_t", eBasicTypeInt128},
{"__uint128_t", eBasicTypeUnsignedInt128},
{"__int128", eBasicTypeInt128},
{"unsigned __int128", eBasicTypeUnsignedInt128},

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we want to leave in the old defines in to make sure it doesn't break anyone? So just add the new entries and leave the old ones?

Comment on lines 162 to 164
EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128_t"));
EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128"));
EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128),
GetBasicQualType("__uint128_t"));
GetBasicQualType("unsigned __int128"));
Copy link
Collaborator

Choose a reason for hiding this comment

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

leave old mappings in?

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've pushed a commit that these tests back.

Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

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

LGTM, just needs API tests for the FindFirstType(...).size cases

@sedymrak
Copy link
Contributor Author

LGTM, just needs API tests for the FindFirstType(...).size cases

That makes sense. I do not have much experience with this but I can try.

@Michael137
Copy link
Member

LGTM, just needs API tests for the FindFirstType(...).size cases

That makes sense. I do not have much experience with this but I can try.

Sure, feel free to ping us here if you have questions!

@sedymrak
Copy link
Contributor Author

LGTM, just needs API tests for the FindFirstType(...).size cases

That makes sense. I do not have much experience with this but I can try.

Sure, feel free to ping us here if you have questions!

In the lldb/unittests/Symbol/TestTypeSystemClang.cpp file there is TestBuiltinTypeForEncodingAndBitSize. If I understand it correctly, this test checks whether ASTContext::getTypeSize() returns proper value for the known basic-types (including __int128 as well as unsigned __int128). When we invoke SBType::GetByteSize() method, that will ultimately boil down to ASTContext::getTypeSize(). I have therefore, for the moment, refrained from adding redundant unit-tests.

I have, instead, pushed a commit that adds a new API test related to this issue.
The test itself does what (I believe) you wanted.
I am not sure whether I have inserted the test in a proper place.

@Michael137
Copy link
Member

Michael137 commented Oct 13, 2025

LGTM, just needs API tests for the FindFirstType(...).size cases

That makes sense. I do not have much experience with this but I can try.

Sure, feel free to ping us here if you have questions!

In the lldb/unittests/Symbol/TestTypeSystemClang.cpp file there is TestBuiltinTypeForEncodingAndBitSize. If I understand it correctly, this test checks whether ASTContext::getTypeSize() returns proper value for the known basic-types (including __int128 as well as unsigned __int128). When we invoke SBType::GetByteSize() method, that will ultimately boil down to ASTContext::getTypeSize(). I have therefore, for the moment, refrained from adding redundant unit-tests.

I have, instead, pushed a commit that adds a new API test related to this issue. The test itself does what (I believe) you wanted. I am not sure whether I have inserted the test in a proper place.

Thanks for adding the test. Left small suggestion. Otherwise LGTM

self.assertEqual(c.GetType().GetBasicType(), int_basic_type)
self.assertEqual(d.GetType().GetBasicType(), int_basic_type)

def testBasicTypeSize(self):
Copy link
Member

Choose a reason for hiding this comment

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

No need to make this a separate test case. Just fold it into the existing case.

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've pushed a commit that joins those two tests back into a single test.

def testBasicTypeSize(self):
"""Check the size of the chosen basic types."""
self.assertEqual(self.target().FindFirstType("__int128").size, 16)
self.assertEqual(self.target().FindFirstType("unsigned __int128").size, 16)
Copy link
Member

Choose a reason for hiding this comment

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

Can we also add the same assertions for __uint128_t and __int128_t?

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've pushed a commit that adds this kind of changes as well.

class TestCase(TestBase):
def test(self):
"""Test that SBType.GetBasicType unwraps typedefs."""
def setUp(self):
Copy link
Member

Choose a reason for hiding this comment

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

Final nit: can we revert the changes of adding a setUp method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for pointing this out. I've missed that. I've pushed a commit that inlines setUp (back) to the test method.

Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

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

thanks for addressing all the comments

@Michael137 Michael137 merged commit 14a1d3e into llvm:main Oct 13, 2025
10 checks passed
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