Skip to content

[lldb][ObjC] Fix method list entry offset calculation #115571

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

Conversation

Michael137
Copy link
Member

The relative_list_list_entry_t offset field in the Objective-C runtime is of type int64_t. There are cases where these offsets are negative values. For negative offsets, LLDB would currently incorrectly zero-extend the offset (dropping the fact that the offset was negative), instead producing large offsets that, when added to the m_baseMethods_ptr result in addresses that had their upper bits set (e.g., 0x00017ff81b3241b0). We then would try to GetMethodList from such an address but fail to read it (because it's an invalid address). This would manifest in Objective-C decls not getting completed correctly (and formatters not working). We noticed this in CI failures on our Intel bots. This happened to work fine on arm64 because we strip the upper bits when calling ClassDescriptorV2::method_list_t::Read using the FixCodeAddress ABI plugin API (which doesn't do that on Intel).

The fix is to sign-extend the offset calculation.

Example failure before this patch:

======================================================================                                                         
FAIL: test_break_dwarf (TestRuntimeTypes.RuntimeTypesTestCase) 
   Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.                                                   
----------------------------------------------------------------------                                                         
Traceback (most recent call last):                                                                                             
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1769, in test_method        
    return attrvalue(self)                                                                                                                                                                                                                                    
  File "/Users/michaelbuch/Git/llvm-project/lldb/test/API/lang/objc/foundation/TestRuntimeTypes.py", line 48, in test_break                                                                                                                                   
    self.expect(                                                                                                                                                                                                                                              
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 2370, in expect                                                                                                                                            
    self.runCmd(                                                                                                               
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1000, in runCmd             
    self.assertTrue(self.res.Succeeded(), msg + output) 
AssertionError: False is not true : Got a valid type                                                                           
Error output:                                                                                                                                                                                                                                                 
error: <user expression 1>:1:11: no known method '+stringWithCString:encoding:'; cast the message send to the method's return type         
    1 | [NSString stringWithCString:"foo" encoding:1]                                                                                                                                                                                                         
      | ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                          
                                                               
Config=x86_64-/Users/michaelbuch/Git/lldb-build-main-no-modules/bin/clang                                                      
----------------------------------------------------------------------      ```

The `relative_list_list_entry_t` offset field in the Objective-C
runtime is of type `int64_t`. There are cases where these offsets
are negative values. For negative offsets, LLDB would currently
incorrectly zero-extend the offset (dropping the fact that the
offset was negative), instead producing large offsets that,
when added to the `m_baseMethods_ptr` result in addresses that
had their upper bits set (e.g., `0x00017ff81b3241b0`). We then
would try to `GetMethodList` from such an address but fail to read
it (because it's an invalid address). This would manifest in
Objective-C decls not getting completed correctly (and formatters not
working). We noticed this in CI failures on our Intel bots. This
happened to work fine on arm64 because we strip the upper bits
when calling `ClassDescriptorV2::method_list_t::Read` using
the `FixCodeAddress` ABI plugin API (which doesn't do that on Intel).

The fix is to sign-extend the offset calculation.
@llvmbot
Copy link
Member

llvmbot commented Nov 9, 2024

@llvm/pr-subscribers-lldb

Author: Michael Buch (Michael137)

Changes

The relative_list_list_entry_t offset field in the Objective-C runtime is of type int64_t. There are cases where these offsets are negative values. For negative offsets, LLDB would currently incorrectly zero-extend the offset (dropping the fact that the offset was negative), instead producing large offsets that, when added to the m_baseMethods_ptr result in addresses that had their upper bits set (e.g., 0x00017ff81b3241b0). We then would try to GetMethodList from such an address but fail to read it (because it's an invalid address). This would manifest in Objective-C decls not getting completed correctly (and formatters not working). We noticed this in CI failures on our Intel bots. This happened to work fine on arm64 because we strip the upper bits when calling ClassDescriptorV2::method_list_t::Read using the FixCodeAddress ABI plugin API (which doesn't do that on Intel).

The fix is to sign-extend the offset calculation.

Example failure before this patch:

======================================================================                                                         
FAIL: test_break_dwarf (TestRuntimeTypes.RuntimeTypesTestCase) 
   Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.                                                   
----------------------------------------------------------------------                                                         
Traceback (most recent call last):                                                                                             
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1769, in test_method        
    return attrvalue(self)                                                                                                                                                                                                                                    
  File "/Users/michaelbuch/Git/llvm-project/lldb/test/API/lang/objc/foundation/TestRuntimeTypes.py", line 48, in test_break                                                                                                                                   
    self.expect(                                                                                                                                                                                                                                              
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 2370, in expect                                                                                                                                            
    self.runCmd(                                                                                                               
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1000, in runCmd             
    self.assertTrue(self.res.Succeeded(), msg + output) 
AssertionError: False is not true : Got a valid type                                                                           
Error output:                                                                                                                                                                                                                                                 
error: &lt;user expression 1&gt;:1:11: no known method '+stringWithCString:encoding:'; cast the message send to the method's return type         
    1 | [NSString stringWithCString:"foo" encoding:1]                                                                                                                                                                                                         
      | ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                          
                                                               
Config=x86_64-/Users/michaelbuch/Git/lldb-build-main-no-modules/bin/clang                                                      
----------------------------------------------------------------------      ```

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


1 Files Affected:

- (modified) lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp (+1-1) 


``````````diff
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
index 39969520b74556..54c9f328b5b78b 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
@@ -394,7 +394,7 @@ bool ClassDescriptorV2::relative_list_entry_t::Read(Process *process,
   lldb::offset_t cursor = 0;
   uint64_t raw_entry = extractor.GetU64_unchecked(&cursor);
   m_image_index = raw_entry & 0xFFFF;
-  m_list_offset = (int64_t)(raw_entry >> 16);
+  m_list_offset = llvm::SignExtend64<48>(raw_entry >> 16);
   return true;
 }
 

@@ -394,7 +394,7 @@ bool ClassDescriptorV2::relative_list_entry_t::Read(Process *process,
lldb::offset_t cursor = 0;
uint64_t raw_entry = extractor.GetU64_unchecked(&cursor);
m_image_index = raw_entry & 0xFFFF;
m_list_offset = (int64_t)(raw_entry >> 16);
m_list_offset = llvm::SignExtend64<48>(raw_entry >> 16);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess that works, too, but why not (int64_t)raw_entry >> 16 ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Just felt more explicit

@Michael137 Michael137 merged commit 04b295e into llvm:main Nov 11, 2024
9 checks passed
@Michael137 Michael137 deleted the bugfix/lldb-objc-method-list-offset-fix branch November 11, 2024 10:06
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Nov 11, 2024
The `relative_list_list_entry_t` offset field in the Objective-C runtime
is of type `int64_t`. There are cases where these offsets are negative
values. For negative offsets, LLDB would currently incorrectly
zero-extend the offset (dropping the fact that the offset was negative),
instead producing large offsets that, when added to the
`m_baseMethods_ptr` result in addresses that had their upper bits set
(e.g., `0x00017ff81b3241b0`). We then would try to `GetMethodList` from
such an address but fail to read it (because it's an invalid address).
This would manifest in Objective-C decls not getting completed correctly
(and formatters not working). We noticed this in CI failures on our
Intel bots. This happened to work fine on arm64 because we strip the
upper bits when calling `ClassDescriptorV2::method_list_t::Read` using
the `FixCodeAddress` ABI plugin API (which doesn't do that on Intel).

The fix is to sign-extend the offset calculation.

Example failure before this patch:
```
======================================================================
FAIL: test_break_dwarf (TestRuntimeTypes.RuntimeTypesTestCase)
   Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1769, in test_method
    return attrvalue(self)
  File "/Users/michaelbuch/Git/llvm-project/lldb/test/API/lang/objc/foundation/TestRuntimeTypes.py", line 48, in test_break
    self.expect(
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 2370, in expect
    self.runCmd(
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1000, in runCmd
    self.assertTrue(self.res.Succeeded(), msg + output)
AssertionError: False is not true : Got a valid type
Error output:
error: <user expression 1>:1:11: no known method '+stringWithCString:encoding:'; cast the message send to the method's return type
    1 | [NSString stringWithCString:"foo" encoding:1]
      | ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Config=x86_64-/Users/michaelbuch/Git/lldb-build-main-no-modules/bin/clang
----------------------------------------------------------------------      ```

(cherry picked from commit 04b295e)
JDevlieghere pushed a commit to swiftlang/llvm-project that referenced this pull request Nov 11, 2024
The `relative_list_list_entry_t` offset field in the Objective-C runtime
is of type `int64_t`. There are cases where these offsets are negative
values. For negative offsets, LLDB would currently incorrectly
zero-extend the offset (dropping the fact that the offset was negative),
instead producing large offsets that, when added to the
`m_baseMethods_ptr` result in addresses that had their upper bits set
(e.g., `0x00017ff81b3241b0`). We then would try to `GetMethodList` from
such an address but fail to read it (because it's an invalid address).
This would manifest in Objective-C decls not getting completed correctly
(and formatters not working). We noticed this in CI failures on our
Intel bots. This happened to work fine on arm64 because we strip the
upper bits when calling `ClassDescriptorV2::method_list_t::Read` using
the `FixCodeAddress` ABI plugin API (which doesn't do that on Intel).

The fix is to sign-extend the offset calculation.

Example failure before this patch:
```
======================================================================
FAIL: test_break_dwarf (TestRuntimeTypes.RuntimeTypesTestCase)
   Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1769, in test_method
    return attrvalue(self)
  File "/Users/michaelbuch/Git/llvm-project/lldb/test/API/lang/objc/foundation/TestRuntimeTypes.py", line 48, in test_break
    self.expect(
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 2370, in expect
    self.runCmd(
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1000, in runCmd
    self.assertTrue(self.res.Succeeded(), msg + output)
AssertionError: False is not true : Got a valid type
Error output:
error: <user expression 1>:1:11: no known method '+stringWithCString:encoding:'; cast the message send to the method's return type
    1 | [NSString stringWithCString:"foo" encoding:1]
      | ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Config=x86_64-/Users/michaelbuch/Git/lldb-build-main-no-modules/bin/clang
----------------------------------------------------------------------      ```

(cherry picked from commit 04b295e)
Groverkss pushed a commit to iree-org/llvm-project that referenced this pull request Nov 15, 2024
The `relative_list_list_entry_t` offset field in the Objective-C runtime
is of type `int64_t`. There are cases where these offsets are negative
values. For negative offsets, LLDB would currently incorrectly
zero-extend the offset (dropping the fact that the offset was negative),
instead producing large offsets that, when added to the
`m_baseMethods_ptr` result in addresses that had their upper bits set
(e.g., `0x00017ff81b3241b0`). We then would try to `GetMethodList` from
such an address but fail to read it (because it's an invalid address).
This would manifest in Objective-C decls not getting completed correctly
(and formatters not working). We noticed this in CI failures on our
Intel bots. This happened to work fine on arm64 because we strip the
upper bits when calling `ClassDescriptorV2::method_list_t::Read` using
the `FixCodeAddress` ABI plugin API (which doesn't do that on Intel).

The fix is to sign-extend the offset calculation.

Example failure before this patch:
```
======================================================================                                                         
FAIL: test_break_dwarf (TestRuntimeTypes.RuntimeTypesTestCase) 
   Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'.                                                   
----------------------------------------------------------------------                                                         
Traceback (most recent call last):                                                                                             
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1769, in test_method        
    return attrvalue(self)                                                                                                                                                                                                                                    
  File "/Users/michaelbuch/Git/llvm-project/lldb/test/API/lang/objc/foundation/TestRuntimeTypes.py", line 48, in test_break                                                                                                                                   
    self.expect(                                                                                                                                                                                                                                              
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 2370, in expect                                                                                                                                            
    self.runCmd(                                                                                                               
  File "/Users/michaelbuch/Git/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 1000, in runCmd             
    self.assertTrue(self.res.Succeeded(), msg + output) 
AssertionError: False is not true : Got a valid type                                                                           
Error output:                                                                                                                                                                                                                                                 
error: <user expression 1>:1:11: no known method '+stringWithCString:encoding:'; cast the message send to the method's return type         
    1 | [NSString stringWithCString:"foo" encoding:1]                                                                                                                                                                                                         
      | ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                          
                                                               
Config=x86_64-/Users/michaelbuch/Git/lldb-build-main-no-modules/bin/clang                                                      
----------------------------------------------------------------------      ```
JDevlieghere added a commit to swiftlang/llvm-project that referenced this pull request Nov 19, 2024
[lldb][ObjC] Fix method list entry offset calculation (llvm#115571)
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