]> git.saurik.com Git - apple/xnu.git/blame - libkdd/kcdata/kcdata_core.m
xnu-3248.60.10.tar.gz
[apple/xnu.git] / libkdd / kcdata / kcdata_core.m
CommitLineData
3e170ce0
A
1/*
2 * Copyright (c) 2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <kern/kern_cdata.h>
30#import <Foundation/Foundation.h>
31#import "kdd.h"
32#import "KCDBasicTypeDescription.h"
33#import "KCDStructTypeDescription.h"
34
35#define MAX_KCDATATYPE_BUFFER_SIZE 2048
36extern struct kcdata_type_definition *kcdata_get_typedescription(unsigned type_id, uint8_t *buffer, uint32_t buffer_size);
37
38
39/*!
40 * @function getTypeFromTypeDef
41 *
42 * @abstract
43 * Build a KCDataType from a type definition.
44 *
45 * @param typeDef
46 * A pointer to kcdata_type_definition_t that specifies the type fields and has subtype definitions
47 * in the memory immediately following the type_definition.
48 *
49 * @return KCDataType * type object which can be used to parse data into dictionaries.
50 * This may return nil if it finds the data to be invalid.
51 *
52 * @discussion
53 * This routine tries to decode the typeDef structure and create either a basic type (KCDBasicTypeDescription)
54 * or a struct type.
55 */
56static KCDataType * getTypeFromTypeDef(struct kcdata_type_definition * typeDef);
57
58static KCDataType *
59getTypeFromTypeDef(struct kcdata_type_definition * typeDef)
60{
61 if (typeDef == NULL) {
62 return nil;
63 }
64 NSString * kct_name = [NSString stringWithFormat:@"%s", typeDef->kct_name];
65 if (typeDef->kct_num_elements == 1) {
66 KCDBasicTypeDescription * retval = [[KCDBasicTypeDescription alloc] initWithKCTypeDesc:&typeDef->kct_elements[0]];
67 return retval;
68 } else {
69 KCDStructTypeDescription * retval =
70 [[KCDStructTypeDescription alloc] initWithType:typeDef->kct_type_identifier withName:kct_name];
71 /* need to do work here to get the array of elements setup here */
72 KCDBasicTypeDescription * curField = nil;
73 for (unsigned int i = 0; i < typeDef->kct_num_elements; i++) {
74 curField = [[KCDBasicTypeDescription alloc] initWithKCTypeDesc:&typeDef->kct_elements[i]];
75 [retval addFieldBasicType:curField];
76 }
77 return retval;
78 }
79 return nil;
80}
81
82KCDataType *
83getKCDataTypeForID(uint32_t typeID)
84{
85 static dispatch_once_t onceToken;
86 static NSMutableDictionary * knownTypes = nil;
87 dispatch_once(&onceToken, ^{
88 if (!knownTypes) {
89 knownTypes = [[NSMutableDictionary alloc] init];
90 }
91 });
92 NSNumber * type = [NSNumber numberWithUnsignedInt:typeID];
93 if (!knownTypes[type]) {
94 /* code to query system for type information */
95 uint8_t buffer[MAX_KCDATATYPE_BUFFER_SIZE];
96 struct kcdata_type_definition * sys_def = kcdata_get_typedescription(typeID, buffer, MAX_KCDATATYPE_BUFFER_SIZE);
97 if (sys_def == NULL) {
98 knownTypes[type] = [[KCDBasicTypeDescription alloc] createDefaultForType:typeID];
99 } else {
100 knownTypes[type] = getTypeFromTypeDef(sys_def);
101 }
102 }
103 assert(knownTypes[type] != nil);
104 return knownTypes[type];
105}
106
107NSString *
108KCDataTypeNameForID(uint32_t typeID)
109{
110 NSString * retval = [NSString stringWithFormat:@"%u", typeID];
111 KCDataType * t = getKCDataTypeForID(typeID);
112
113 if (![[t name] containsString:@"Type_"]) {
114 retval = [t name];
115 }
116 return retval;
117}
118
119NSMutableDictionary *
120parseKCDataArray(void * dataBuffer)
121{
122 uint32_t typeID = KCDATA_ITEM_ARRAY_GET_EL_TYPE(dataBuffer);
123 uint32_t count = KCDATA_ITEM_ARRAY_GET_EL_COUNT(dataBuffer);
124 uint32_t size = KCDATA_ITEM_ARRAY_GET_EL_SIZE(dataBuffer);
125 uint8_t * buffer = (uint8_t *)KCDATA_ITEM_DATA_PTR(dataBuffer);
126 KCDataType * datatype = getKCDataTypeForID(typeID);
127 NSMutableDictionary * retval = [[NSMutableDictionary alloc] initWithCapacity:1];
128 NSMutableArray * arr = [[NSMutableArray alloc] initWithCapacity:count];
129 retval[[datatype name]] = arr;
130 NSMutableDictionary * tmpdict = NULL;
131 for (uint32_t i = 0; i < count; i++) {
132 tmpdict = [datatype parseData:(void *)&buffer[i * size] ofLength:size];
133 [arr addObject:tmpdict];
134 }
135 return retval;
136}
137
138NSMutableDictionary *
139parseKCDataContainer(void * dataBuffer, uint32_t * bytesParsed)
140{
141 if (bytesParsed == NULL)
142 return nil;
143 assert(KCDATA_ITEM_TYPE(dataBuffer) == KCDATA_TYPE_CONTAINER_BEGIN);
144 uint64_t containerID = KCDATA_CONTAINER_ID(dataBuffer);
145
146 /* setup collection object for sub containers */
147 NSMutableDictionary * sub_containers = [[NSMutableDictionary alloc] init];
148 NSMutableDictionary * retval = [[NSMutableDictionary alloc] init];
149 NSMutableDictionary * container = [[NSMutableDictionary alloc] init];
150 struct kcdata_item * buffer = (struct kcdata_item *)KCDATA_ITEM_NEXT_HEADER(dataBuffer);
151 KCDataType * tmptype;
152 uint32_t _t;
153 void * _d;
154 NSMutableDictionary * tmpdict;
155 retval[KCDataTypeNameForID(kcdata_get_container_type(dataBuffer))] = container;
156
157 KCDATA_ITEM_FOREACH(buffer)
158 {
159 _t = KCDATA_ITEM_TYPE(buffer);
160 _d = KCDATA_ITEM_DATA_PTR(buffer);
161 if (_t == KCDATA_TYPE_CONTAINER_END) {
162 if (KCDATA_CONTAINER_ID(buffer) == containerID) {
163 break;
164 }
165 continue;
166 }
167
168 if (_t == KCDATA_TYPE_ARRAY) {
169 tmpdict = parseKCDataArray(buffer);
170 [container addEntriesFromDictionary:tmpdict];
171 continue;
172 }
173
174 if (_t == KCDATA_TYPE_CONTAINER_BEGIN) {
175 uint32_t container_size = 0;
176 tmpdict = parseKCDataContainer(buffer, &container_size);
177 NSString * subcontainerID = [NSString stringWithFormat:@"%llu", KCDATA_CONTAINER_ID(buffer)];
178 NSString * k_desc = nil;
179 assert([tmpdict count] == 1);
180 for (NSString * k in [tmpdict keyEnumerator]) {
181 k_desc = k;
182 if ([k intValue] != 0)
183 k_desc = KCDataTypeNameForID([k intValue]);
184
185 if ([sub_containers objectForKey:k_desc] == nil) {
186 sub_containers[k_desc] = [[NSMutableDictionary alloc] init];
187 }
188 sub_containers[k_desc][subcontainerID] = tmpdict[k];
189 }
190 buffer = (struct kcdata_item *)((uintptr_t)buffer + container_size);
191 if (KCDATA_ITEM_TYPE(buffer) == KCDATA_TYPE_BUFFER_END) {
192 break;
193 }
194 continue;
195 }
196
197 tmptype = getKCDataTypeForID(_t);
198 tmpdict = [tmptype parseData:_d ofLength:KCDATA_ITEM_SIZE(buffer)];
199 if ([tmpdict count] == 1)
200 [container addEntriesFromDictionary:tmpdict];
201 else
202 container[[tmptype name]] = tmpdict;
203 }
204 [container addEntriesFromDictionary:sub_containers];
205 *bytesParsed = (uint32_t)((uintptr_t)buffer - (uintptr_t)dataBuffer);
206 return retval;
207}