Skip to content

Commit 2fd9697

Browse files
authored
Merge pull request #6729 from jasonmolenda/r108306070-off-by-one-armv7-macho-corefile-59
Fix off-by-one error in armv7 mach-o corefile register context
2 parents 7fee1ab + beb1399 commit 2fd9697

File tree

4 files changed

+297
-11
lines changed

4 files changed

+297
-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
@@ -534,21 +534,18 @@ class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm {
534534
lldb::offset_t next_thread_state = offset + (count * 4);
535535
switch (flavor) {
536536
case GPRAltRegSet:
537-
case GPRRegSet:
538-
// On ARM, the CPSR register is also included in the count but it is
539-
// not included in gpr.r so loop until (count-1).
540-
541-
// Prevent static analysis warnings by explicitly contstraining 'count'
542-
// to acceptable range. Handle possible underflow of count-1
543-
if (count > 0 && count <= sizeof(gpr.r) / sizeof(gpr.r[0])) {
537+
case GPRRegSet: {
538+
// r0-r15, plus CPSR
539+
uint32_t gpr_buf_count = (sizeof(gpr.r) / sizeof(gpr.r[0])) + 1;
540+
if (count == gpr_buf_count) {
544541
for (uint32_t i = 0; i < (count - 1); ++i) {
545542
gpr.r[i] = data.GetU32(&offset);
546543
}
547-
}
548-
// Save cpsr explicitly.
549-
gpr.cpsr = data.GetU32(&offset);
544+
gpr.cpsr = data.GetU32(&offset);
550545

551-
SetError(GPRRegSet, Read, 0);
546+
SetError(GPRRegSet, Read, 0);
547+
}
548+
}
552549
offset = next_thread_state;
553550
break;
554551

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

0 commit comments

Comments
 (0)