aboutsummaryrefslogtreecommitdiffstats
path: root/system_cmds/zlog.tproj/SymbolicationHelper.c
blob: 68a128595c66e0ab374debd846e3edc9b4e587df (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//
//  SymbolicationHelper.c
//  zlog
//
//  Created by Rasha Eqbal on 2/26/18.
//

#include "SymbolicationHelper.h"

/*
 * Most of the CoreSymbolication code here has been copied from ioclasscount in the IOKitTools project.
 */

#define kAddressKey CFSTR("Address")
#define kNameKey CFSTR("Name")
#define kPathKey CFSTR("Path")
#define kSegmentsKey CFSTR("Segments")
#define kSizeKey CFSTR("Size")
#define kUuidKey CFSTR("UUID")

static void AddSymbolOwnerSummary(CSSymbolOwnerRef owner, CFMutableDictionaryRef binaryImages);
static void ShowBinaryImage(const void *key, const void *value, void *context);

/*
 * Symbolicates 'addr' using the 'symbolicator' passed in.
 * Adds owner info to 'binaryImages' for offline symbolication.
 *
 * Top-level function that needs to be called on each frame address in the backtrace.
 */
void PrintSymbolicatedAddress(CSSymbolicatorRef symbolicator, mach_vm_address_t addr, CFMutableDictionaryRef binaryImages)
{
	printf("0x%llx", addr);

	CSSymbolOwnerRef ownerInfo = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(symbolicator, addr, kCSNow);
	if (!CSIsNull(ownerInfo)) {
		const char *moduleName = CSSymbolOwnerGetName(ownerInfo);
		if (moduleName) {
			printf(" <%s>", moduleName);
		}
	}

	CSSymbolRef symbolInfo = CSSymbolicatorGetSymbolWithAddressAtTime(symbolicator, addr, kCSNow);
	if (!CSIsNull(symbolInfo)) {
		printf(" %s", CSSymbolGetName(symbolInfo));
	}

	CSSourceInfoRef sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(symbolicator, addr, kCSNow);
	if (!CSIsNull(sourceInfo)) {
		const char *fileName = CSSourceInfoGetPath(sourceInfo);
		if (fileName) {
			printf(" at %s:%d", fileName, CSSourceInfoGetLineNumber(sourceInfo));
		}
	}
	printf("\n");

	AddSymbolOwnerSummary(ownerInfo, binaryImages);
}

/*
 * Adds symbolication information for 'owner' to 'binaryImages' to help with offline symbolication.
 *
 * This is called from PrintSymbolicatedAddress() on the symbol owner for each address it symbolicates.
 */
static void AddSymbolOwnerSummary(CSSymbolOwnerRef owner, CFMutableDictionaryRef binaryImages)
{
	const CFUUIDBytes *uuidBytes = NULL;
	CFUUIDRef uuid = NULL;
	CFStringRef uuidString = NULL, path = NULL, name = NULL;
	CFMutableDictionaryRef summaryDict = NULL;
	__block CSSegmentRef textSegment = kCSNull, textExecSegment = kCSNull;
	CSSegmentRef segment = kCSNull;
	CSRange range;
	CFNumberRef address = NULL, size = NULL;

#define RETURN_IF_NULL(ptr)	\
if (!(ptr))	{			\
goto cleanup;		\
}

	uuidBytes = CSSymbolOwnerGetCFUUIDBytes(owner);
	if (uuidBytes) {
		uuid = CFUUIDCreateFromUUIDBytes(NULL, *uuidBytes);
		if (uuid) {
			uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuid);
		}
	}
	RETURN_IF_NULL(uuidString);

	if (!CFDictionaryContainsKey(binaryImages, uuidString)) {
		summaryDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
		RETURN_IF_NULL(summaryDict);

		CFDictionarySetValue(summaryDict, kUuidKey, uuidString);

		path = CFStringCreateWithCString(kCFAllocatorDefault, CSSymbolOwnerGetPath(owner), kCFStringEncodingUTF8);
		RETURN_IF_NULL(path);
		CFDictionarySetValue(summaryDict, kPathKey, path);

		name = CFStringCreateWithCString(kCFAllocatorDefault, CSSymbolOwnerGetName(owner), kCFStringEncodingUTF8);
		RETURN_IF_NULL(name);
		CFDictionarySetValue(summaryDict, kNameKey, name);

		CSSymbolOwnerForeachSegment(owner, ^(CSSegmentRef segment) {
			if (strcmp(CSRegionGetName(segment), "__TEXT SEGMENT") == 0) {
				textSegment = segment;
				CSRetain(textSegment);
			} else if (strcmp(CSRegionGetName(segment), "__TEXT_EXEC SEGMENT") == 0) {
				textExecSegment = segment;
				CSRetain(textExecSegment);
			}
		});

		segment = !CSIsNull(textExecSegment) ? textExecSegment : textSegment;
		if (CSIsNull(segment)) {
			goto cleanup;
		}
		range = CSRegionGetRange(segment);

		address = CFNumberCreate(NULL, kCFNumberLongLongType, &range.location);
		RETURN_IF_NULL(address);
		CFDictionarySetValue(summaryDict, kAddressKey, address);

		size = CFNumberCreate(NULL, kCFNumberLongLongType, &range.length);
		RETURN_IF_NULL(size);
		CFDictionarySetValue(summaryDict, kSizeKey, size);

		CFDictionarySetValue(binaryImages, uuidString, summaryDict);
	}

cleanup:
	if (size) CFRelease(size);
	if (address) CFRelease(address);
	if (!CSIsNull(textExecSegment)) CSRelease(textExecSegment);
	if (!CSIsNull(textSegment)) CSRelease(textSegment);
	if (name) CFRelease(name);
	if (path) CFRelease(path);
	if (summaryDict) CFRelease(summaryDict);
	if (uuidString) CFRelease(uuidString);
	if (uuid) CFRelease(uuid);
}

/*
 * Prints offline symbolication information for the images passed in 'binaryImages'.
 *
 * Top-level function that needs to be called if the tool wants to include support
 * for offline symbolication.
 */
void PrintBinaryImagesInfo(CFMutableDictionaryRef binaryImages)
{
	if (CFDictionaryGetCount(binaryImages) > 0) {
		printf("\nBinary Images:\n");
		CFDictionaryApplyFunction(binaryImages, ShowBinaryImage, NULL);
	} else {
		printf("No binary images\n");
	}
}

/*
 * Prints information about a binary image necessary for offline symbolication.
 *
 * This is called from PrintBinaryImagesInfo() on each element in 'binaryImages'.
 */
static void ShowBinaryImage(const void *key, const void *value, void *context)
{
	char nameString[256] = {0}, uuidString[256] = {0}, pathString[256] = {0};
	CFStringRef uuid = (CFStringRef)key;
	CFStringGetCString(uuid, uuidString, sizeof(uuidString), kCFStringEncodingASCII);
	CFDictionaryRef summary = (CFDictionaryRef)value;

	CFStringRef name = CFDictionaryGetValue(summary, kNameKey);
	CFStringGetCString(name, nameString, sizeof(nameString), kCFStringEncodingASCII);
	CFStringRef path = CFDictionaryGetValue(summary, kPathKey);
	CFStringGetCString(path, pathString, sizeof(pathString), kCFStringEncodingASCII);
	CFNumberRef addressNumber = CFDictionaryGetValue(summary, kAddressKey);
	CFNumberRef sizeNumber = CFDictionaryGetValue(summary, kSizeKey);
	int64_t address, size;
	CFNumberGetValue(addressNumber, kCFNumberSInt64Type, &address);
	CFNumberGetValue(sizeNumber, kCFNumberSInt64Type, &size);

	printf("%p - %p %s <%s> %s\n", (void*)address, (void*)address + size, nameString, uuidString, pathString);
}