Skip to content

Commit 6b6bac2

Browse files
committed
Fix off-by-one error in armv7 mach-o corefile register context
The sanity check on the size of the register context we found in the corefile was off by one, so lldb would not add the register contents. Add a test case to ensure it doesn't regress. Differential Revision: https://reviews.llvm.org/D149224 rdar://108306070
1 parent 6e8ce16 commit 6b6bac2

File tree

4 files changed

+282
-11
lines changed

4 files changed

+282
-11
lines changed

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -531,21 +531,18 @@ class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm {
531531
lldb::offset_t next_thread_state = offset + (count * 4);
532532
switch (flavor) {
533533
case GPRAltRegSet:
534-
case GPRRegSet:
535-
// On ARM, the CPSR register is also included in the count but it is
536-
// not included in gpr.r so loop until (count-1).
537-
538-
// Prevent static analysis warnings by explicitly contstraining 'count'
539-
// to acceptable range. Handle possible underflow of count-1
540-
if (count > 0 && count <= sizeof(gpr.r) / sizeof(gpr.r[0])) {
534+
case GPRRegSet: {
535+
// r0-r15, plus CPSR
536+
uint32_t gpr_buf_count = (sizeof(gpr.r) / sizeof(gpr.r[0])) + 1;
537+
if (count == gpr_buf_count) {
541538
for (uint32_t i = 0; i < (count - 1); ++i) {
542539
gpr.r[i] = data.GetU32(&offset);
543540
}
544-
}
545-
// Save cpsr explicitly.
546-
gpr.cpsr = data.GetU32(&offset);
541+
gpr.cpsr = data.GetU32(&offset);
547542

548-
SetError(GPRRegSet, Read, 0);
543+
SetError(GPRRegSet, Read, 0);
544+
}
545+
}
549546
offset = next_thread_state;
550547
break;
551548

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
MAKE_DSYM := NO
2+
3+
CXX_SOURCES := create-arm-corefiles.cpp
4+
5+
include Makefile.rules
6+
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Test that Mach-O armv7/arm64 corefile register contexts are read by lldb."""
2+
3+
4+
5+
import os
6+
import re
7+
import subprocess
8+
9+
import lldb
10+
from lldbsuite.test.decorators import *
11+
from lldbsuite.test.lldbtest import *
12+
from lldbsuite.test import lldbutil
13+
14+
class TestArmMachoCorefileRegctx(TestBase):
15+
16+
NO_DEBUG_INFO_TESTCASE = True
17+
@skipUnlessDarwin
18+
19+
def setUp(self):
20+
TestBase.setUp(self)
21+
self.build()
22+
self.create_corefile = self.getBuildArtifact("a.out")
23+
self.corefile = self.getBuildArtifact("core")
24+
25+
def test_armv7_corefile(self):
26+
### Create corefile
27+
retcode = call(self.create_corefile + " armv7 " + self.corefile, shell=True)
28+
29+
target = self.dbg.CreateTarget('')
30+
err = lldb.SBError()
31+
process = target.LoadCore(self.corefile)
32+
self.assertEqual(process.IsValid(), True)
33+
thread = process.GetSelectedThread()
34+
frame = thread.GetSelectedFrame()
35+
36+
lr = frame.FindRegister("lr")
37+
self.assertTrue(lr.IsValid())
38+
self.assertEqual(lr.GetValueAsUnsigned(), 0x000f0000)
39+
40+
pc = frame.FindRegister("pc")
41+
self.assertTrue(pc.IsValid())
42+
self.assertEqual(pc.GetValueAsUnsigned(), 0x00100000)
43+
44+
exception = frame.FindRegister("exception")
45+
self.assertTrue(exception.IsValid())
46+
self.assertEqual(exception.GetValueAsUnsigned(), 0x00003f5c)
47+
48+
def test_arm64_corefile(self):
49+
### Create corefile
50+
retcode = call(self.create_corefile + " arm64 " + self.corefile, shell=True)
51+
52+
target = self.dbg.CreateTarget('')
53+
err = lldb.SBError()
54+
process = target.LoadCore(self.corefile)
55+
self.assertEqual(process.IsValid(), True)
56+
thread = process.GetSelectedThread()
57+
frame = thread.GetSelectedFrame()
58+
59+
lr = frame.FindRegister("lr")
60+
self.assertTrue(lr.IsValid())
61+
self.assertEqual(lr.GetValueAsUnsigned(), 0x000000018cd97f28)
62+
63+
pc = frame.FindRegister("pc")
64+
self.assertTrue(pc.IsValid())
65+
self.assertEqual(pc.GetValueAsUnsigned(), 0x0000000100003f5c)
66+
67+
exception = frame.FindRegister("far")
68+
self.assertTrue(exception.IsValid())
69+
self.assertEqual(exception.GetValueAsUnsigned(), 0x0000000100003f5c)
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
#include <mach-o/loader.h>
2+
#include <mach/thread_status.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string>
6+
#include <vector>
7+
8+
union uint32_buf {
9+
uint8_t bytebuf[4];
10+
uint32_t val;
11+
};
12+
13+
union uint64_buf {
14+
uint8_t bytebuf[8];
15+
uint64_t val;
16+
};
17+
18+
void add_uint64(std::vector<uint8_t> &buf, uint64_t val) {
19+
uint64_buf conv;
20+
conv.val = val;
21+
for (int i = 0; i < 8; i++)
22+
buf.push_back(conv.bytebuf[i]);
23+
}
24+
25+
void add_uint32(std::vector<uint8_t> &buf, uint32_t val) {
26+
uint32_buf conv;
27+
conv.val = val;
28+
for (int i = 0; i < 4; i++)
29+
buf.push_back(conv.bytebuf[i]);
30+
}
31+
32+
std::vector<uint8_t> armv7_lc_thread_load_command() {
33+
std::vector<uint8_t> data;
34+
add_uint32(data, LC_THREAD); // thread_command.cmd
35+
add_uint32(data, 104); // thread_command.cmdsize
36+
add_uint32(data, ARM_THREAD_STATE); // thread_command.flavor
37+
add_uint32(data, ARM_THREAD_STATE_COUNT); // thread_command.count
38+
add_uint32(data, 0x00010000); // r0
39+
add_uint32(data, 0x00020000); // r1
40+
add_uint32(data, 0x00030000); // r2
41+
add_uint32(data, 0x00040000); // r3
42+
add_uint32(data, 0x00050000); // r4
43+
add_uint32(data, 0x00060000); // r5
44+
add_uint32(data, 0x00070000); // r6
45+
add_uint32(data, 0x00080000); // r7
46+
add_uint32(data, 0x00090000); // r8
47+
add_uint32(data, 0x000a0000); // r9
48+
add_uint32(data, 0x000b0000); // r10
49+
add_uint32(data, 0x000c0000); // r11
50+
add_uint32(data, 0x000d0000); // r12
51+
add_uint32(data, 0x000e0000); // sp
52+
add_uint32(data, 0x000f0000); // lr
53+
add_uint32(data, 0x00100000); // pc
54+
add_uint32(data, 0x00110000); // cpsr
55+
56+
add_uint32(data, ARM_EXCEPTION_STATE); // thread_command.flavor
57+
add_uint32(data, ARM_EXCEPTION_STATE_COUNT); // thread_command.count
58+
add_uint32(data, 0x00003f5c); // far
59+
add_uint32(data, 0xf2000000); // esr
60+
add_uint32(data, 0x00000000); // exception
61+
62+
return data;
63+
}
64+
65+
std::vector<uint8_t> arm64_lc_thread_load_command() {
66+
std::vector<uint8_t> data;
67+
add_uint32(data, LC_THREAD); // thread_command.cmd
68+
add_uint32(data, 312); // thread_command.cmdsize
69+
add_uint32(data, ARM_THREAD_STATE64); // thread_command.flavor
70+
add_uint32(data, ARM_THREAD_STATE64_COUNT); // thread_command.count
71+
add_uint64(data, 0x0000000000000001); // x0
72+
add_uint64(data, 0x000000016fdff3c0); // x1
73+
add_uint64(data, 0x000000016fdff3d0); // x2
74+
add_uint64(data, 0x000000016fdff510); // x3
75+
add_uint64(data, 0x0000000000000000); // x4
76+
add_uint64(data, 0x0000000000000000); // x5
77+
add_uint64(data, 0x0000000000000000); // x6
78+
add_uint64(data, 0x0000000000000000); // x7
79+
add_uint64(data, 0x000000010000d910); // x8
80+
add_uint64(data, 0x0000000000000001); // x9
81+
add_uint64(data, 0xe1e88de000000000); // x10
82+
add_uint64(data, 0x0000000000000003); // x11
83+
add_uint64(data, 0x0000000000000148); // x12
84+
add_uint64(data, 0x0000000000004000); // x13
85+
add_uint64(data, 0x0000000000000008); // x14
86+
add_uint64(data, 0x0000000000000000); // x15
87+
add_uint64(data, 0x0000000000000000); // x16
88+
add_uint64(data, 0x0000000100003f5c); // x17
89+
add_uint64(data, 0x0000000000000000); // x18
90+
add_uint64(data, 0x0000000100003f5c); // x19
91+
add_uint64(data, 0x000000010000c000); // x20
92+
add_uint64(data, 0x000000010000d910); // x21
93+
add_uint64(data, 0x000000016fdff250); // x22
94+
add_uint64(data, 0x000000018ce12366); // x23
95+
add_uint64(data, 0x000000016fdff1d0); // x24
96+
add_uint64(data, 0x0000000000000001); // x25
97+
add_uint64(data, 0x0000000000000000); // x26
98+
add_uint64(data, 0x0000000000000000); // x27
99+
add_uint64(data, 0x0000000000000000); // x28
100+
add_uint64(data, 0x000000016fdff3a0); // fp
101+
add_uint64(data, 0x000000018cd97f28); // lr
102+
add_uint64(data, 0x000000016fdff140); // sp
103+
add_uint64(data, 0x0000000100003f5c); // pc
104+
add_uint32(data, 0x80001000); // cpsr
105+
106+
add_uint32(data, 0x00000000); // padding
107+
108+
add_uint32(data, ARM_EXCEPTION_STATE64); // thread_command.flavor
109+
add_uint32(data, ARM_EXCEPTION_STATE64_COUNT); // thread_command.count
110+
add_uint64(data, 0x0000000100003f5c); // far
111+
add_uint32(data, 0xf2000000); // esr
112+
add_uint32(data, 0x00000000); // exception
113+
114+
return data;
115+
}
116+
117+
enum arch { unspecified, armv7, arm64 };
118+
119+
int main(int argc, char **argv) {
120+
if (argc != 3) {
121+
fprintf(stderr,
122+
"usage: create-arm-corefiles [armv7|arm64] <output-core-name>\n");
123+
exit(1);
124+
}
125+
126+
arch arch = unspecified;
127+
128+
if (strcmp(argv[1], "armv7") == 0)
129+
arch = armv7;
130+
else if (strcmp(argv[1], "arm64") == 0)
131+
arch = arm64;
132+
else {
133+
fprintf(stderr, "unrecognized architecture %s\n", argv[1]);
134+
exit(1);
135+
}
136+
137+
// An array of load commands (in the form of byte arrays)
138+
std::vector<std::vector<uint8_t>> load_commands;
139+
140+
// An array of corefile contents (page data, lc_note data, etc)
141+
std::vector<uint8_t> payload;
142+
143+
// First add all the load commands / payload so we can figure out how large
144+
// the load commands will actually be.
145+
if (arch == armv7)
146+
load_commands.push_back(armv7_lc_thread_load_command());
147+
else if (arch == arm64)
148+
load_commands.push_back(arm64_lc_thread_load_command());
149+
150+
int size_of_load_commands = 0;
151+
for (const auto &lc : load_commands)
152+
size_of_load_commands += lc.size();
153+
154+
int header_and_load_cmd_room =
155+
sizeof(struct mach_header_64) + size_of_load_commands;
156+
157+
// Erase the load commands / payload now that we know how much space is
158+
// needed, redo it.
159+
load_commands.clear();
160+
payload.clear();
161+
162+
if (arch == armv7)
163+
load_commands.push_back(armv7_lc_thread_load_command());
164+
else if (arch == arm64)
165+
load_commands.push_back(arm64_lc_thread_load_command());
166+
167+
struct mach_header_64 mh;
168+
mh.magic = MH_MAGIC_64;
169+
if (arch == armv7) {
170+
mh.cputype = CPU_TYPE_ARM;
171+
mh.cpusubtype = CPU_SUBTYPE_ARM_V7M;
172+
} else if (arch == arm64) {
173+
mh.cputype = CPU_TYPE_ARM64;
174+
mh.cpusubtype = CPU_SUBTYPE_ARM64_ALL;
175+
}
176+
mh.filetype = MH_CORE;
177+
mh.ncmds = load_commands.size();
178+
mh.sizeofcmds = size_of_load_commands;
179+
mh.flags = 0;
180+
mh.reserved = 0;
181+
182+
FILE *f = fopen(argv[2], "w");
183+
184+
if (f == nullptr) {
185+
fprintf(stderr, "Unable to open file %s for writing\n", argv[2]);
186+
exit(1);
187+
}
188+
189+
fwrite(&mh, sizeof(struct mach_header_64), 1, f);
190+
191+
for (const auto &lc : load_commands)
192+
fwrite(lc.data(), lc.size(), 1, f);
193+
194+
fseek(f, header_and_load_cmd_room, SEEK_SET);
195+
196+
fwrite(payload.data(), payload.size(), 1, f);
197+
198+
fclose(f);
199+
}

0 commit comments

Comments
 (0)