]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/dyld_usage_json.dtest/main.mm
dyld-832.7.1.tar.gz
[apple/dyld.git] / testing / test-cases / dyld_usage_json.dtest / main.mm
1 // BUILD(macos): $CC foo.c -o $BUILD_DIR/libfoo.dylib -dynamiclib -install_name $RUN_DIR/lifoo.dylib
2 // BUILD(macos): $CC target.c -o $BUILD_DIR/dyld_usage_target.exe -DRUN_DIR="$RUN_DIR"
3 // BUILD(macos): $CXX main.mm -o $BUILD_DIR/dyld_usage_json.exe -DRUN_DIR="$RUN_DIR" -std=c++14 -framework Foundation
4
5 // BUILD(ios,tvos,watchos,bridgeos):
6
7 // RUN: $SUDO ./dyld_usage_json.exe
8
9 #import <Foundation/Foundation.h>
10
11 #include <errno.h>
12 #include <signal.h>
13 #include <spawn.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
16
17 #include <map>
18 #include <sstream>
19 #include <string>
20 #include <vector>
21
22 #include "test_support.h"
23
24 enum class NodeValueType {
25 Default,
26 String,
27 RawValue,
28 };
29
30 struct Node
31 {
32 NodeValueType type = NodeValueType::Default;
33 std::string value;
34 std::map<std::string, Node> map;
35 std::vector<Node> array;
36
37 inline Node()
38 : type(NodeValueType::Default), value(), map(), array() { }
39
40 inline Node(std::string string)
41 : type(NodeValueType::String), value(string), map(), array() { }
42
43 inline Node(const char *string) : Node(std::string(string)) { }
44
45 inline Node(bool b)
46 : type(NodeValueType::RawValue), value(b ? "true" : "false")
47 , map(), array() { }
48
49 inline Node(int64_t i64)
50 : type(NodeValueType::RawValue), value(), map(), array()
51 {
52 std::ostringstream os;
53 os << i64;
54 value = os.str();
55 }
56
57 inline Node(uint64_t u64)
58 : type(NodeValueType::RawValue), value(), map(), array()
59 {
60 std::ostringstream os;
61 os << u64;
62 value = os.str();
63 }
64 };
65
66 static Node parseNode(id jsonObject) {
67 __block Node node;
68
69 // NSDictionary -> map
70 if ([jsonObject isKindOfClass:[NSDictionary class]]) {
71 NSDictionary* dict = (NSDictionary*)jsonObject;
72
73 [dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
74 if (![key isKindOfClass:[NSString class]]) {
75 fprintf(stderr, "JSON map key is not of string type\n");
76 *stop = true;
77 return;
78 }
79 Node childNode = parseNode(value);
80
81 node.map[[key UTF8String]] = childNode;
82 }];
83
84 return node;
85 }
86
87 // NSArray -> array
88 if ([jsonObject isKindOfClass:[NSArray class]]) {
89 NSArray* array = (NSArray*)jsonObject;
90
91 [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
92 Node childNode = parseNode(obj);
93 node.array.push_back(childNode);
94 }];
95
96 return node;
97 }
98
99 // NSString -> value
100 if ([jsonObject isKindOfClass:[NSString class]]) {
101 node.value = [(NSString*)jsonObject UTF8String];
102 return node;
103 }
104
105 fprintf(stderr, "Unknown json deserialized type\n");
106 return Node();
107 }
108
109 Node readJSON(const void * contents, size_t length) {
110 NSData* data = [NSData dataWithBytes:contents length:length];
111 NSError* error = nil;
112 id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
113 if (!jsonObject) {
114 fprintf(stderr, "Could not deserialize json because '%s'",[[error localizedFailureReason] UTF8String]);
115 return Node();
116 }
117
118 return parseNode(jsonObject);
119 }
120
121 char* mergeJsonRoots(char* jsonBuffer, size_t size)
122 {
123 char *mergedJson = (char*)malloc((size + 2) * sizeof(char));
124 mergedJson[0] = '[';
125 mergedJson[size+1] = '\0';
126 mergedJson[size+1] = ']';
127 for (size_t i = 0; i < size; i++) {
128 mergedJson[i+1] = jsonBuffer[i];
129 if (jsonBuffer[i] == '\n') {
130 if ( i > 0 && i < size - 1 ) {
131 if (jsonBuffer[i-1] == '}' && jsonBuffer[i+1] == '{')
132 mergedJson[i+1] = ',';
133 }
134 }
135 }
136 return mergedJson;
137 }
138
139 void validateJson(Node json, pid_t pid)
140 {
141 size_t expectedSize = 4;
142 if (json.array.size() != expectedSize)
143 FAIL("dyld_usage reported number of events is incorrect. Reported %lu instead of %lu", json.array.size(), expectedSize);
144
145 std::string handle = json.array[1].map["event"].map["result"].value;
146
147 for (size_t i = 0; i < json.array.size(); i++) {
148
149 if ( json.array[i].map["command"].value.compare("dyld_usage_target.exe") != 0 )
150 FAIL("Incorrect command name for event at index %lu", i);
151
152 int jpid = std::stoi(json.array[i].map["pid"].value);
153 if ( jpid != pid)
154 FAIL("Incorrect pid for event at index %lu. Reported %d intead of %d (%s)", i, jpid, pid, json.array[i].map["pid"].value.c_str());
155
156 if (i == 0) {
157 if ( json.array[i].map["event"].map["type"].value.compare("app_launch") != 0 )
158 FAIL("dyld_usage did not report app launch event");
159 }
160
161 if (i == 1) {
162 if ( json.array[1].map["event"].map["type"].value.compare("dlopen") != 0 )
163 FAIL("dyld_usage did not report dlopen event");
164 if ( json.array[1].map["event"].map["path"].value.compare(RUN_DIR "/libfoo.dylib") != 0 )
165 FAIL("Incorrect dlopen library path");
166 }
167
168 if (i == 2) {
169 if ( json.array[i].map["event"].map["type"].value.compare("dlsym") != 0 )
170 FAIL("dyld_usage did not report dlsym event");
171 if ( json.array[i].map["event"].map["symbol"].value.compare("foo") != 0 )
172 FAIL("incorrect dlsym symbol reported");
173 if ( json.array[i].map["event"].map["handle"].value.compare(handle) != 0 )
174 FAIL("dlsym handle does not match dlopen result");
175 }
176
177 if (i == 3) {
178 if ( json.array[i].map["event"].map["type"].value.compare("dlclose") != 0 )
179 FAIL("dyld_usage did not report dlclose event");
180 if ( json.array[i].map["event"].map["handle"].value.compare(handle) != 0 )
181 FAIL("dlclose handle does not match dlopen result");
182 }
183 }
184 }
185
186 int main(int argc, const char* argv[], char *env[])
187 {
188 _process dyldUsage;
189 dyldUsage.set_executable_path("/usr/local/bin/dyld_usage");
190 dyldUsage.set_launch_async(true);
191 const char* args[] = { "-j", "dyld_usage_target.exe", NULL };
192 dyldUsage.set_args(args);
193 __block dispatch_data_t output = NULL;
194 dyldUsage.set_stdout_handler(^(int fd) {
195 ssize_t size = 0;
196 do {
197 char buffer[16384] = {0};
198 size = read(fd, buffer, 16384);
199 if ( size == -1 )
200 break;
201 dispatch_data_t data = dispatch_data_create(buffer, size, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
202 output = output ? dispatch_data_create_concat(output, data) : data;
203 } while ( size > 0 );
204 });
205
206 pid_t pid = dyldUsage.launch();
207 usleep(2000000);
208
209 // Launch target
210 _process target;
211 target.set_executable_path(RUN_DIR "/dyld_usage_target.exe");
212 pid_t tpid = target.launch();
213
214 usleep(2000000);
215 // Kill dyld_usage
216 kill(pid, SIGTERM);
217
218
219 int status;
220 if (waitpid(pid, &status, 0) == -1)
221 FAIL("waitpid failed");
222 if ( !output )
223 FAIL("No dyld_usage output");
224
225 const void* buffer;
226 size_t size;
227 (void)dispatch_data_create_map(output, &buffer, &size);
228 char* jsonBuffer = mergeJsonRoots((char*)buffer, size);
229 size += 2;
230 Node node = readJSON(jsonBuffer, size);
231 free(jsonBuffer);
232 validateJson(node, tpid);
233
234 PASS("Success");
235 return 0;
236 }