--- /dev/null
+"""Test that Mach-O armv7/arm64 corefile register contexts are read by lldb."""
+
+
+
+import os
+import re
+import subprocess
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestArmMachoCorefileRegctx(TestBase):
+
+ NO_DEBUG_INFO_TESTCASE = True
+ @skipUnlessDarwin
+
+ def setUp(self):
+ TestBase.setUp(self)
+ self.build()
+ self.create_corefile = self.getBuildArtifact("a.out")
+ self.corefile = self.getBuildArtifact("core")
+
+ def test_armv7_corefile(self):
+ ### Create corefile
+ retcode = call(self.create_corefile + " armv7 " + self.corefile, shell=True)
+
+ target = self.dbg.CreateTarget('')
+ err = lldb.SBError()
+ process = target.LoadCore(self.corefile)
+ self.assertEqual(process.IsValid(), True)
+ thread = process.GetSelectedThread()
+ frame = thread.GetSelectedFrame()
+
+ lr = frame.FindRegister("lr")
+ self.assertTrue(lr.IsValid())
+ self.assertEqual(lr.GetValueAsUnsigned(), 0x000f0000)
+
+ pc = frame.FindRegister("pc")
+ self.assertTrue(pc.IsValid())
+ self.assertEqual(pc.GetValueAsUnsigned(), 0x00100000)
+
+ exception = frame.FindRegister("exception")
+ self.assertTrue(exception.IsValid())
+ self.assertEqual(exception.GetValueAsUnsigned(), 0x00003f5c)
+
+ def test_arm64_corefile(self):
+ ### Create corefile
+ retcode = call(self.create_corefile + " arm64 " + self.corefile, shell=True)
+
+ target = self.dbg.CreateTarget('')
+ err = lldb.SBError()
+ process = target.LoadCore(self.corefile)
+ self.assertEqual(process.IsValid(), True)
+ thread = process.GetSelectedThread()
+ frame = thread.GetSelectedFrame()
+
+ lr = frame.FindRegister("lr")
+ self.assertTrue(lr.IsValid())
+ self.assertEqual(lr.GetValueAsUnsigned(), 0x000000018cd97f28)
+
+ pc = frame.FindRegister("pc")
+ self.assertTrue(pc.IsValid())
+ self.assertEqual(pc.GetValueAsUnsigned(), 0x0000000100003f5c)
+
+ exception = frame.FindRegister("far")
+ self.assertTrue(exception.IsValid())
+ self.assertEqual(exception.GetValueAsUnsigned(), 0x0000000100003f5c)
--- /dev/null
+#include <mach-o/loader.h>
+#include <mach/thread_status.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <vector>
+
+union uint32_buf {
+ uint8_t bytebuf[4];
+ uint32_t val;
+};
+
+union uint64_buf {
+ uint8_t bytebuf[8];
+ uint64_t val;
+};
+
+void add_uint64(std::vector<uint8_t> &buf, uint64_t val) {
+ uint64_buf conv;
+ conv.val = val;
+ for (int i = 0; i < 8; i++)
+ buf.push_back(conv.bytebuf[i]);
+}
+
+void add_uint32(std::vector<uint8_t> &buf, uint32_t val) {
+ uint32_buf conv;
+ conv.val = val;
+ for (int i = 0; i < 4; i++)
+ buf.push_back(conv.bytebuf[i]);
+}
+
+std::vector<uint8_t> armv7_lc_thread_load_command() {
+ std::vector<uint8_t> data;
+ add_uint32(data, LC_THREAD); // thread_command.cmd
+ add_uint32(data, 104); // thread_command.cmdsize
+ add_uint32(data, ARM_THREAD_STATE); // thread_command.flavor
+ add_uint32(data, ARM_THREAD_STATE_COUNT); // thread_command.count
+ add_uint32(data, 0x00010000); // r0
+ add_uint32(data, 0x00020000); // r1
+ add_uint32(data, 0x00030000); // r2
+ add_uint32(data, 0x00040000); // r3
+ add_uint32(data, 0x00050000); // r4
+ add_uint32(data, 0x00060000); // r5
+ add_uint32(data, 0x00070000); // r6
+ add_uint32(data, 0x00080000); // r7
+ add_uint32(data, 0x00090000); // r8
+ add_uint32(data, 0x000a0000); // r9
+ add_uint32(data, 0x000b0000); // r10
+ add_uint32(data, 0x000c0000); // r11
+ add_uint32(data, 0x000d0000); // r12
+ add_uint32(data, 0x000e0000); // sp
+ add_uint32(data, 0x000f0000); // lr
+ add_uint32(data, 0x00100000); // pc
+ add_uint32(data, 0x00110000); // cpsr
+
+ add_uint32(data, ARM_EXCEPTION_STATE); // thread_command.flavor
+ add_uint32(data, ARM_EXCEPTION_STATE_COUNT); // thread_command.count
+ add_uint32(data, 0x00003f5c); // far
+ add_uint32(data, 0xf2000000); // esr
+ add_uint32(data, 0x00000000); // exception
+
+ return data;
+}
+
+std::vector<uint8_t> arm64_lc_thread_load_command() {
+ std::vector<uint8_t> data;
+ add_uint32(data, LC_THREAD); // thread_command.cmd
+ add_uint32(data, 312); // thread_command.cmdsize
+ add_uint32(data, ARM_THREAD_STATE64); // thread_command.flavor
+ add_uint32(data, ARM_THREAD_STATE64_COUNT); // thread_command.count
+ add_uint64(data, 0x0000000000000001); // x0
+ add_uint64(data, 0x000000016fdff3c0); // x1
+ add_uint64(data, 0x000000016fdff3d0); // x2
+ add_uint64(data, 0x000000016fdff510); // x3
+ add_uint64(data, 0x0000000000000000); // x4
+ add_uint64(data, 0x0000000000000000); // x5
+ add_uint64(data, 0x0000000000000000); // x6
+ add_uint64(data, 0x0000000000000000); // x7
+ add_uint64(data, 0x000000010000d910); // x8
+ add_uint64(data, 0x0000000000000001); // x9
+ add_uint64(data, 0xe1e88de000000000); // x10
+ add_uint64(data, 0x0000000000000003); // x11
+ add_uint64(data, 0x0000000000000148); // x12
+ add_uint64(data, 0x0000000000004000); // x13
+ add_uint64(data, 0x0000000000000008); // x14
+ add_uint64(data, 0x0000000000000000); // x15
+ add_uint64(data, 0x0000000000000000); // x16
+ add_uint64(data, 0x0000000100003f5c); // x17
+ add_uint64(data, 0x0000000000000000); // x18
+ add_uint64(data, 0x0000000100003f5c); // x19
+ add_uint64(data, 0x000000010000c000); // x20
+ add_uint64(data, 0x000000010000d910); // x21
+ add_uint64(data, 0x000000016fdff250); // x22
+ add_uint64(data, 0x000000018ce12366); // x23
+ add_uint64(data, 0x000000016fdff1d0); // x24
+ add_uint64(data, 0x0000000000000001); // x25
+ add_uint64(data, 0x0000000000000000); // x26
+ add_uint64(data, 0x0000000000000000); // x27
+ add_uint64(data, 0x0000000000000000); // x28
+ add_uint64(data, 0x000000016fdff3a0); // fp
+ add_uint64(data, 0x000000018cd97f28); // lr
+ add_uint64(data, 0x000000016fdff140); // sp
+ add_uint64(data, 0x0000000100003f5c); // pc
+ add_uint32(data, 0x80001000); // cpsr
+
+ add_uint32(data, 0x00000000); // padding
+
+ add_uint32(data, ARM_EXCEPTION_STATE64); // thread_command.flavor
+ add_uint32(data, ARM_EXCEPTION_STATE64_COUNT); // thread_command.count
+ add_uint64(data, 0x0000000100003f5c); // far
+ add_uint32(data, 0xf2000000); // esr
+ add_uint32(data, 0x00000000); // exception
+
+ return data;
+}
+
+enum arch { unspecified, armv7, arm64 };
+
+int main(int argc, char **argv) {
+ if (argc != 3) {
+ fprintf(stderr,
+ "usage: create-arm-corefiles [armv7|arm64] <output-core-name>\n");
+ exit(1);
+ }
+
+ arch arch = unspecified;
+
+ if (strcmp(argv[1], "armv7") == 0)
+ arch = armv7;
+ else if (strcmp(argv[1], "arm64") == 0)
+ arch = arm64;
+ else {
+ fprintf(stderr, "unrecognized architecture %s\n", argv[1]);
+ exit(1);
+ }
+
+ // An array of load commands (in the form of byte arrays)
+ std::vector<std::vector<uint8_t>> load_commands;
+
+ // An array of corefile contents (page data, lc_note data, etc)
+ std::vector<uint8_t> payload;
+
+ // First add all the load commands / payload so we can figure out how large
+ // the load commands will actually be.
+ if (arch == armv7)
+ load_commands.push_back(armv7_lc_thread_load_command());
+ else if (arch == arm64)
+ load_commands.push_back(arm64_lc_thread_load_command());
+
+ int size_of_load_commands = 0;
+ for (const auto &lc : load_commands)
+ size_of_load_commands += lc.size();
+
+ int header_and_load_cmd_room =
+ sizeof(struct mach_header_64) + size_of_load_commands;
+
+ // Erase the load commands / payload now that we know how much space is
+ // needed, redo it.
+ load_commands.clear();
+ payload.clear();
+
+ if (arch == armv7)
+ load_commands.push_back(armv7_lc_thread_load_command());
+ else if (arch == arm64)
+ load_commands.push_back(arm64_lc_thread_load_command());
+
+ struct mach_header_64 mh;
+ mh.magic = MH_MAGIC_64;
+ if (arch == armv7) {
+ mh.cputype = CPU_TYPE_ARM;
+ mh.cpusubtype = CPU_SUBTYPE_ARM_V7M;
+ } else if (arch == arm64) {
+ mh.cputype = CPU_TYPE_ARM64;
+ mh.cpusubtype = CPU_SUBTYPE_ARM64_ALL;
+ }
+ mh.filetype = MH_CORE;
+ mh.ncmds = load_commands.size();
+ mh.sizeofcmds = size_of_load_commands;
+ mh.flags = 0;
+ mh.reserved = 0;
+
+ FILE *f = fopen(argv[2], "w");
+
+ if (f == nullptr) {
+ fprintf(stderr, "Unable to open file %s for writing\n", argv[2]);
+ exit(1);
+ }
+
+ fwrite(&mh, sizeof(struct mach_header_64), 1, f);
+
+ for (const auto &lc : load_commands)
+ fwrite(lc.data(), lc.size(), 1, f);
+
+ fseek(f, header_and_load_cmd_room, SEEK_SET);
+
+ fwrite(payload.data(), payload.size(), 1, f);
+
+ fclose(f);
+}