jasonmolenda created this revision.
jasonmolenda added a reviewer: JDevlieghere.
jasonmolenda added a project: LLDB.
Herald added subscribers: omjavaid, kristof.beyls.
jasonmolenda requested review of this revision.

For ARMv8.3 pointer auth signing, lldb needs to know how many bits are valid 
for addressing, and strip the high bits off of addresses before looking them 
up.  During the initial bringup, we didn't have dynamic ways of getting these 
values so we hardcoded a default addressing mask in lldb, and there are still 
some cases where we need to support this, where we still don't have the value 
dynamically declared.

There are three parts to this patch, all needed to construct a test.  The most 
important part is that when I print ptrauth values, I always print the actual 
uint64_t with ptrauth bits included, then I strip the bits and see if it 
resolves to an address that lldb knows about.  If so, then I use the normal 
formatter.  For this test case, I needed this behavior in our function pointer 
formatter.  Our normal output might look like

(lldb) p fmain
(int (*)(...)) $0 = 0x0000000100003f90 (a.out`main at main.c:3)

and with an ARMv8.3 ABI with ptrauth bits, you might see

(lldb) p fmain
(int (*)(...)) $0 = 0xe46bff0100003f8c (0xe46bff0100003f8c)

which is not helpful.  So this patch does

(lldb) p fmain
(int (*)(...)) $0 = 0xe46bff0100003f8c (actual=0x0000000100003f8c a.out`main at 
main.c:3)

I never want to hide the ptrauth bit reality from the user - because they may 
be debugging a problem with ptrauth signing itself.  The three parts of the 
patch:

1. ABIMacOSX_arm64::FixAddress changed so if no mask is specified, uses the 
default mask.

2. ObjectFileMachO::GetAllArchSpecs when reading a Mach-O binary, we were 
previously clearing the Vendor from the Triple that we create for the binary 
(so it would be arm64e--).  This loses information - realistically, any binary 
in a Mach-O container is most likely following the Darwin ABIs and I want to 
retain the vendor so we can select the correct ABI instead of grabbing any 
random arm64 ABI.

3. ArchSpec::SetArchitecture - explicitly set the vendor to Apple when we have 
a Mach-O architecture.

4. formatters::CXXFunctionPointerSummaryProvider the formatter change above.

The test case for this is a main.c with main() and a function pointer global to 
main, fmain().  Then there is a standalone program that creates this specific 
corefile without any metadata about the addressing bits -- lldb itself always 
adds this metadata, so I couldn't use lldb's built-in process save-core 
functionality. It's a tiny corefile that only has 8 bytes of DATA memory where 
the function pointer is stored.  I have ideas for how I can use this test case 
for some upcoming changes I want to make, so I expect to get more use out of 
this test case.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115431

Files:
  lldb/source/DataFormatters/CXXFunctionPointer.cpp
  lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
  lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
  lldb/source/Utility/ArchSpec.cpp
  lldb/test/API/macosx/corefile-default-ptrauth/Makefile
  lldb/test/API/macosx/corefile-default-ptrauth/TestCorefileDefaultPtrauth.py
  lldb/test/API/macosx/corefile-default-ptrauth/create-corefile.c
  lldb/test/API/macosx/corefile-default-ptrauth/main.c

Index: lldb/test/API/macosx/corefile-default-ptrauth/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/corefile-default-ptrauth/main.c
@@ -0,0 +1,6 @@
+int main();
+int (*fmain)() = main;
+int main () {
+  return fmain();
+}
+
Index: lldb/test/API/macosx/corefile-default-ptrauth/create-corefile.c
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/corefile-default-ptrauth/create-corefile.c
@@ -0,0 +1,105 @@
+#include <mach-o/loader.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach/machine.h>
+#include <string.h>
+#include <mach/machine/thread_state.h>
+#include <inttypes.h>
+#include <sys/syslimits.h>
+
+// Given an executable binary with 
+//   "fmain" (a function pointer to main)
+//   "main"
+// symbols, create a fake arm64e corefile that
+// contains a memory segment for the fmain 
+// function pointer, with the value of the 
+// address of main() with ptrauth bits masked on.
+//
+// The corefile does not include the "addrable bits"
+// LC_NOTE, so lldb will need to fall back on its 
+// default value from the Darwin arm64 ABI.
+
+int main(int argc, char **argv)
+{
+  if (argc != 3) {
+    fprintf (stderr, "usage: %s executable-binary output-file\n", argv[0]);
+    exit(1);
+  }
+  FILE *exe = fopen(argv[1], "r");
+  if (!exe) {
+    fprintf (stderr, "Unable to open executable %s for reading\n", argv[1]);
+  }
+  FILE *out = fopen(argv[2], "w");
+  if (!out) {
+    fprintf (stderr, "Unable to open %s for writing\n", argv[2]);
+    exit(1);
+  }
+
+  char buf[PATH_MAX + 6];
+  sprintf (buf, "nm '%s'", argv[1]);
+  FILE *nm = popen(buf, "r");
+  if (!nm) {
+    fprintf (stderr, "Unable to run nm on '%s'", argv[1]);
+    exit (1);
+  }
+  uint64_t main_addr = 0;
+  uint64_t fmain_addr = 0;
+  while (fgets (buf, sizeof(buf), nm)) {
+    if (strstr (buf, "_fmain")) {
+      fmain_addr = strtoul (buf, NULL, 16);
+    }
+    if (strstr (buf, "_main")) {
+      main_addr = strtoul (buf, NULL, 16);
+    }
+  }
+  fclose (nm);
+
+  int size_of_thread_cmd = 4 + 4 + 4 + 4 + sizeof (arm_thread_state64_t);
+
+  struct mach_header_64 mh;
+  mh.magic = 0xfeedfacf;
+  mh.cputype = CPU_TYPE_ARM64;
+  mh.cpusubtype = CPU_SUBTYPE_ARM64E;
+  mh.filetype = MH_CORE;
+  mh.ncmds = 2;
+  mh.sizeofcmds = sizeof(struct segment_command_64) + size_of_thread_cmd;
+  mh.flags = 0;
+  mh.reserved = 0;
+
+  fwrite(&mh, sizeof (mh), 1, out);
+
+  struct segment_command_64 seg;
+  seg.cmd = LC_SEGMENT_64;
+  seg.cmdsize = sizeof(seg);
+  memset (&seg.segname, 0, 16);
+  seg.vmaddr = fmain_addr;
+  seg.vmsize = 8;
+  seg.fileoff = sizeof (mh) + sizeof(seg) + size_of_thread_cmd;
+  seg.filesize = 8;
+  seg.maxprot = 3;
+  seg.initprot = 3;
+  seg.nsects = 0;
+  seg.flags = 0;
+
+  fwrite (&seg, sizeof (seg), 1, out);
+
+  uint32_t cmd = LC_THREAD;
+  fwrite (&cmd, sizeof (cmd), 1, out);
+  uint32_t cmdsize = size_of_thread_cmd;
+  fwrite (&cmdsize, sizeof (cmdsize), 1, out);
+  uint32_t flavor = ARM_THREAD_STATE64;
+  fwrite (&flavor, sizeof (flavor), 1, out);
+  uint32_t count = sizeof (arm_thread_state64_t) / 4;
+  fwrite (&count, sizeof (count), 1, out);
+  arm_thread_state64_t regstate;
+  memset (&regstate, 0, sizeof (regstate));
+  fwrite (&regstate, sizeof (regstate), 1, out);
+
+
+  uint64_t segment_contents = 0xe46bff0000000000 | main_addr;
+
+  fwrite (&segment_contents, sizeof (segment_contents), 1, out);
+
+  fclose (out);
+
+}
Index: lldb/test/API/macosx/corefile-default-ptrauth/TestCorefileDefaultPtrauth.py
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/corefile-default-ptrauth/TestCorefileDefaultPtrauth.py
@@ -0,0 +1,50 @@
+"""Test that lldb has a default mask for addressable bits on Darwin arm64 ABI"""
+
+
+import os
+import re
+import subprocess
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCorefileDefaultPtrauth(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
+    @skipIf(archs=no_match(['arm64','arm64e']))
+    @skipUnlessDarwin
+    def test_lc_note(self):
+        self.build()
+        self.test_exe = self.getBuildArtifact("a.out")
+        self.create_corefile = self.getBuildArtifact("create-corefile")
+        self.corefile = self.getBuildArtifact("core")
+
+        ### Create our corefile
+        retcode = call(self.create_corefile + " " +  self.test_exe + " " + self.corefile, shell=True)
+
+        ## This corefile has no metadata telling us how many bits are
+        ## used for ptrauth signed function pointers.  We will need lldb
+        ## to fall back on its old default value for Darwin arm64 ABIs
+        ## to correctly strip the bits.
+
+        self.target = self.dbg.CreateTarget('')
+        err = lldb.SBError()
+        self.process = self.target.LoadCore(self.corefile)
+        self.assertEqual(self.process.IsValid(), True)
+        modspec = lldb.SBModuleSpec()
+        modspec.SetFileSpec(lldb.SBFileSpec(self.test_exe, True))
+        m = self.target.AddModule(modspec)
+        self.assertTrue(m.IsValid())
+        self.target.SetModuleLoadAddress (m, 0)
+        
+        # target variable should show us both the actual function
+        # pointer with ptrauth bits and the symbol it resolves to,
+        # with the ptrauth bits stripped, e.g.
+        #  (int (*)(...)) fmain = 0xe46bff0100003f90 (actual=0x0000000100003f90 a.out`main at main.c:3)
+
+        self.expect("ta v fmain", substrs=['fmain = 0x', 'actual=0x', 'main at main.c'])
Index: lldb/test/API/macosx/corefile-default-ptrauth/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/corefile-default-ptrauth/Makefile
@@ -0,0 +1,9 @@
+C_SOURCES := main.c
+
+all: a.out create-corefile
+
+create-corefile:
+	$(MAKE) -f $(MAKEFILE_RULES) EXE=create-corefile \
+		C_SOURCES=create-corefile.c
+
+include Makefile.rules
Index: lldb/source/Utility/ArchSpec.cpp
===================================================================
--- lldb/source/Utility/ArchSpec.cpp
+++ lldb/source/Utility/ArchSpec.cpp
@@ -859,6 +859,7 @@
         m_triple.setArchName(llvm::StringRef(core_def->name));
         if (arch_type == eArchTypeMachO) {
           m_triple.setVendor(llvm::Triple::Apple);
+          m_triple.setObjectFormat(llvm::Triple::MachO);
 
           // Don't set the OS.  It could be simulator, macosx, ios, watchos,
           // tvos, bridgeos.  We could get close with the cpu type - but we
Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -5158,11 +5158,6 @@
       base_triple.setVendor(llvm::Triple::Apple);
       add_triple(base_triple);
     } else {
-      // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT
-      // so lets not say our Vendor is Apple, leave it as an unspecified
-      // unknown.
-      base_triple.setVendor(llvm::Triple::UnknownVendor);
-      base_triple.setVendorName(llvm::StringRef());
       add_triple(base_triple);
     }
   }
Index: lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
===================================================================
--- lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
+++ lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
@@ -817,6 +817,16 @@
 
 lldb::addr_t ABIMacOSX_arm64::FixAddress(addr_t pc, addr_t mask) {
   lldb::addr_t pac_sign_extension = 0x0080000000000000ULL;
+  // Darwin systems originally couldn't determine the proper value
+  // dynamically, so the most common value was hardcoded.  This has
+  // largely been cleaned up, but there are still a handful of
+  // environments that assume the default value is set to this value
+  // and there's no dynamic value to correct it.
+  // When no mask is specified, set it to 39 bits of addressing (0..38).
+  if (mask == 0) {
+    // ~((1ULL<<39)-1)
+    mask = 0xffffff8000000000;
+  }
   return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
 }
 
Index: lldb/source/DataFormatters/CXXFunctionPointer.cpp
===================================================================
--- lldb/source/DataFormatters/CXXFunctionPointer.cpp
+++ lldb/source/DataFormatters/CXXFunctionPointer.cpp
@@ -9,6 +9,7 @@
 #include "lldb/DataFormatters/CXXFunctionPointer.h"
 
 #include "lldb/Core/ValueObject.h"
+#include "lldb/Target/ABI.h"
 #include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Utility/Stream.h"
@@ -38,8 +39,34 @@
       Address so_addr;
       Target *target = exe_ctx.GetTargetPtr();
       if (target && !target->GetSectionLoadList().IsEmpty()) {
-        if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address,
-                                                            so_addr)) {
+        target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address,
+                                                            so_addr);
+        if (so_addr.GetSection() == nullptr) {
+          // If we have an address that doesn't correspond to any symbol,
+          // it might have authentication bits.  Strip them & see if it
+          // now points to a symbol -- if so, do the SymbolContext lookup
+          // based on the stripped address.
+          // If we find a symbol with the ptrauth bits stripped, print the
+          // raw value into the stream, and replace the Address with the
+          // one that points to a symbol for a fuller description.
+          Process *process = exe_ctx.GetProcessPtr();
+          if (process) {
+            if (ABISP abi_sp = process->GetABI()) {
+              addr_t fixed_addr = abi_sp->FixCodeAddress (func_ptr_address);
+              if (fixed_addr != func_ptr_address) {
+                Address test_address;
+                test_address.SetLoadAddress (fixed_addr, target);
+                if (test_address.GetSection() != nullptr) {
+                  int addrsize = target->GetArchitecture().GetAddressByteSize();
+                  sstr.Printf("actual=0x%*.*" PRIx64 " ", addrsize * 2, addrsize * 2, fixed_addr);
+                  so_addr = test_address;
+                }
+              }
+            }
+          }
+        }
+
+        if (so_addr.IsValid()) {
           so_addr.Dump(&sstr, exe_ctx.GetBestExecutionContextScope(),
                        Address::DumpStyleResolvedDescription,
                        Address::DumpStyleSectionNameOffset);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to