1*4d495c6eSApple OSS Distributions // clang++ -o kt-dump{,.cpp} -Wall -std=c++20
2*4d495c6eSApple OSS Distributions
3*4d495c6eSApple OSS Distributions #include <assert.h>
4*4d495c6eSApple OSS Distributions #include <cstdio>
5*4d495c6eSApple OSS Distributions #include <filesystem>
6*4d495c6eSApple OSS Distributions #include <fstream>
7*4d495c6eSApple OSS Distributions #include <iostream>
8*4d495c6eSApple OSS Distributions #include <mach-o/fat.h>
9*4d495c6eSApple OSS Distributions #include <mach-o/loader.h>
10*4d495c6eSApple OSS Distributions #include <optional>
11*4d495c6eSApple OSS Distributions #include <set>
12*4d495c6eSApple OSS Distributions #include <span>
13*4d495c6eSApple OSS Distributions #include <vector>
14*4d495c6eSApple OSS Distributions #include <removefile.h>
15*4d495c6eSApple OSS Distributions #include <unistd.h>
16*4d495c6eSApple OSS Distributions #include <spawn.h>
17*4d495c6eSApple OSS Distributions #include <fcntl.h>
18*4d495c6eSApple OSS Distributions #include <uuid/uuid.h>
19*4d495c6eSApple OSS Distributions
20*4d495c6eSApple OSS Distributions /*
21*4d495c6eSApple OSS Distributions * kt-dump.cpp
22*4d495c6eSApple OSS Distributions *
23*4d495c6eSApple OSS Distributions * Tool to dump the kalloc type information from a given Mach-O binary.
24*4d495c6eSApple OSS Distributions * Usage:
25*4d495c6eSApple OSS Distributions * kt-dump [-f <simple|json|struct|stats>] <mach-o>
26*4d495c6eSApple OSS Distributions *
27*4d495c6eSApple OSS Distributions * The tool will scan the given Mach-O to find the __kalloc_type section.
28*4d495c6eSApple OSS Distributions * It will then walk that section using the kalloc_type_view definition
29*4d495c6eSApple OSS Distributions * provided below, in order to dump the type names and signatures that
30*4d495c6eSApple OSS Distributions * have been compiled into the binary.
31*4d495c6eSApple OSS Distributions *
32*4d495c6eSApple OSS Distributions * The output "format" can be specified with the -f option. The default
33*4d495c6eSApple OSS Distributions * format ("simple") will output the type name and the signature,
34*4d495c6eSApple OSS Distributions * enclosed in square brackets. The "json" format will print a JSON
35*4d495c6eSApple OSS Distributions * dictionary for each kalloc_type_view entry, including the type name,
36*4d495c6eSApple OSS Distributions * its size and the signature. The "struct" output format will use
37*4d495c6eSApple OSS Distributions * __builtin_dump_struct to dump a C-like representation of the view.
38*4d495c6eSApple OSS Distributions * Finally, if the "stats" output format is chosen, the tool will only
39*4d495c6eSApple OSS Distributions * show overall information about the __kalloc_type section.
40*4d495c6eSApple OSS Distributions *
41*4d495c6eSApple OSS Distributions * The tool supports both MH_KEXT_BUNDLE and kernel cache files. If a
42*4d495c6eSApple OSS Distributions * FAT Mach-O is provided, it must contain an arm64 slice.
43*4d495c6eSApple OSS Distributions */
44*4d495c6eSApple OSS Distributions
45*4d495c6eSApple OSS Distributions /* Note: these must be kept in sync with the defs in kalloc.h/zalloc.h */
46*4d495c6eSApple OSS Distributions
47*4d495c6eSApple OSS Distributions __options_decl(kalloc_type_flags_t, uint32_t, {
48*4d495c6eSApple OSS Distributions KT_DEFAULT = 0x0001,
49*4d495c6eSApple OSS Distributions KT_PRIV_ACCT = 0x0002,
50*4d495c6eSApple OSS Distributions KT_SHARED_ACCT = 0x0004,
51*4d495c6eSApple OSS Distributions KT_DATA_ONLY = 0x0008,
52*4d495c6eSApple OSS Distributions KT_VM = 0x0010,
53*4d495c6eSApple OSS Distributions KT_CHANGED = 0x0020,
54*4d495c6eSApple OSS Distributions KT_CHANGED2 = 0x0040,
55*4d495c6eSApple OSS Distributions KT_PTR_ARRAY = 0x0080,
56*4d495c6eSApple OSS Distributions KT_NOEARLY = 0x2000,
57*4d495c6eSApple OSS Distributions KT_SLID = 0x4000,
58*4d495c6eSApple OSS Distributions KT_PROCESSED = 0x8000,
59*4d495c6eSApple OSS Distributions KT_HASH = 0xffff0000,
60*4d495c6eSApple OSS Distributions });
61*4d495c6eSApple OSS Distributions
62*4d495c6eSApple OSS Distributions __options_decl(kalloc_type_version_t, uint16_t, {
63*4d495c6eSApple OSS Distributions KT_V1 = 0x0001,
64*4d495c6eSApple OSS Distributions });
65*4d495c6eSApple OSS Distributions
66*4d495c6eSApple OSS Distributions /* fixme we need to recognize Intel for which this is 20*/
67*4d495c6eSApple OSS Distributions #define KHEAP_NUM_ZONES 22
68*4d495c6eSApple OSS Distributions
69*4d495c6eSApple OSS Distributions struct zone_view {
70*4d495c6eSApple OSS Distributions void *zv_zone;
71*4d495c6eSApple OSS Distributions void *zv_stats;
72*4d495c6eSApple OSS Distributions const char *zv_name;
73*4d495c6eSApple OSS Distributions void *zv_next;
74*4d495c6eSApple OSS Distributions };
75*4d495c6eSApple OSS Distributions
76*4d495c6eSApple OSS Distributions struct kalloc_type_view {
77*4d495c6eSApple OSS Distributions struct zone_view kt_zv;
78*4d495c6eSApple OSS Distributions const char *kt_signature;
79*4d495c6eSApple OSS Distributions kalloc_type_flags_t kt_flags;
80*4d495c6eSApple OSS Distributions uint32_t kt_size;
81*4d495c6eSApple OSS Distributions struct zone *kt_zearly;
82*4d495c6eSApple OSS Distributions struct zone *kt_zsig;
83*4d495c6eSApple OSS Distributions };
84*4d495c6eSApple OSS Distributions
85*4d495c6eSApple OSS Distributions struct kalloc_type_var_view {
86*4d495c6eSApple OSS Distributions kalloc_type_version_t kt_version;
87*4d495c6eSApple OSS Distributions uint16_t kt_size_hdr;
88*4d495c6eSApple OSS Distributions /*
89*4d495c6eSApple OSS Distributions * Temporary: Needs to be 32bits cause we have many structs that use
90*4d495c6eSApple OSS Distributions * IONew/Delete that are larger than 32K.
91*4d495c6eSApple OSS Distributions */
92*4d495c6eSApple OSS Distributions uint32_t kt_size_type;
93*4d495c6eSApple OSS Distributions struct zone_stats *kt_stats;
94*4d495c6eSApple OSS Distributions const char *kt_name;
95*4d495c6eSApple OSS Distributions struct zone_view *kt_next;
96*4d495c6eSApple OSS Distributions uint16_t kt_heap_start;
97*4d495c6eSApple OSS Distributions uint8_t kt_zones[KHEAP_NUM_ZONES];
98*4d495c6eSApple OSS Distributions const char *kt_sig_hdr;
99*4d495c6eSApple OSS Distributions const char *kt_sig_type;
100*4d495c6eSApple OSS Distributions kalloc_type_flags_t kt_flags;
101*4d495c6eSApple OSS Distributions };
102*4d495c6eSApple OSS Distributions
103*4d495c6eSApple OSS Distributions template <typename T> struct macho_section {
104*4d495c6eSApple OSS Distributions section_64 section;
105*4d495c6eSApple OSS Distributions std::span<const T> contents;
106*4d495c6eSApple OSS Distributions
macho_sectionmacho_section107*4d495c6eSApple OSS Distributions macho_section(const section_64 &sec, std::span<uint8_t> data)
108*4d495c6eSApple OSS Distributions : section(sec),
109*4d495c6eSApple OSS Distributions contents(reinterpret_cast<T *>(
110*4d495c6eSApple OSS Distributions data.subspan(sec.offset, sec.size / sizeof(T)).data()),
111*4d495c6eSApple OSS Distributions sec.size / sizeof(T))
112*4d495c6eSApple OSS Distributions {
113*4d495c6eSApple OSS Distributions }
114*4d495c6eSApple OSS Distributions
115*4d495c6eSApple OSS Distributions size_t
elem_sizemacho_section116*4d495c6eSApple OSS Distributions elem_size() const
117*4d495c6eSApple OSS Distributions {
118*4d495c6eSApple OSS Distributions return sizeof(T);
119*4d495c6eSApple OSS Distributions }
120*4d495c6eSApple OSS Distributions
121*4d495c6eSApple OSS Distributions size_t
elem_countmacho_section122*4d495c6eSApple OSS Distributions elem_count() const
123*4d495c6eSApple OSS Distributions {
124*4d495c6eSApple OSS Distributions return section.size / elem_size();
125*4d495c6eSApple OSS Distributions }
126*4d495c6eSApple OSS Distributions };
127*4d495c6eSApple OSS Distributions
128*4d495c6eSApple OSS Distributions int
printf_with_indent(const char * indent,const char * format,...)129*4d495c6eSApple OSS Distributions printf_with_indent(const char *indent, const char *format, ...)
130*4d495c6eSApple OSS Distributions {
131*4d495c6eSApple OSS Distributions int n = 0;
132*4d495c6eSApple OSS Distributions
133*4d495c6eSApple OSS Distributions va_list ap;
134*4d495c6eSApple OSS Distributions if (*indent) {
135*4d495c6eSApple OSS Distributions std::cout << indent;
136*4d495c6eSApple OSS Distributions n += strlen(indent);
137*4d495c6eSApple OSS Distributions }
138*4d495c6eSApple OSS Distributions
139*4d495c6eSApple OSS Distributions va_start(ap, format);
140*4d495c6eSApple OSS Distributions n += vprintf(format, ap);
141*4d495c6eSApple OSS Distributions va_end(ap);
142*4d495c6eSApple OSS Distributions return n;
143*4d495c6eSApple OSS Distributions }
144*4d495c6eSApple OSS Distributions
145*4d495c6eSApple OSS Distributions static inline const char *
decode_string(const macho_section<char> & sec_cstring,const char * string)146*4d495c6eSApple OSS Distributions decode_string(const macho_section<char> &sec_cstring, const char *string)
147*4d495c6eSApple OSS Distributions {
148*4d495c6eSApple OSS Distributions /*
149*4d495c6eSApple OSS Distributions * Compute the offsets into the __cstring section.
150*4d495c6eSApple OSS Distributions * This works for both single kexts (MH_KEXT_BUNDLE) and kernel caches.
151*4d495c6eSApple OSS Distributions * For the former, the __cstring section addr is the offset of the section
152*4d495c6eSApple OSS Distributions * into the slice. For the latter, the __cstring section addr is the virtual
153*4d495c6eSApple OSS Distributions * address of the section, and the fields are pointers into such space.
154*4d495c6eSApple OSS Distributions */
155*4d495c6eSApple OSS Distributions
156*4d495c6eSApple OSS Distributions if (string) {
157*4d495c6eSApple OSS Distributions uintptr_t string_p = reinterpret_cast<uintptr_t>(string);
158*4d495c6eSApple OSS Distributions uint32_t string_off = (uint32_t)string_p;
159*4d495c6eSApple OSS Distributions
160*4d495c6eSApple OSS Distributions return &sec_cstring.contents[string_off - sec_cstring.section.offset];
161*4d495c6eSApple OSS Distributions }
162*4d495c6eSApple OSS Distributions
163*4d495c6eSApple OSS Distributions return nullptr;
164*4d495c6eSApple OSS Distributions }
165*4d495c6eSApple OSS Distributions
166*4d495c6eSApple OSS Distributions static enum class out_fmt_type {
167*4d495c6eSApple OSS Distributions SIMPLE,
168*4d495c6eSApple OSS Distributions JSON,
169*4d495c6eSApple OSS Distributions STRUCT,
170*4d495c6eSApple OSS Distributions STATS
171*4d495c6eSApple OSS Distributions } out_fmt = out_fmt_type::SIMPLE;
172*4d495c6eSApple OSS Distributions
173*4d495c6eSApple OSS Distributions class image {
174*4d495c6eSApple OSS Distributions const std::span<uint8_t> slice_contents;
175*4d495c6eSApple OSS Distributions size_t slice_mh_offs;
176*4d495c6eSApple OSS Distributions
177*4d495c6eSApple OSS Distributions std::optional<macho_section<kalloc_type_view> > sec_types;
178*4d495c6eSApple OSS Distributions std::optional<macho_section<kalloc_type_var_view> > sec_types_var;
179*4d495c6eSApple OSS Distributions std::optional<macho_section<char> > sec_cstring;
180*4d495c6eSApple OSS Distributions uuid_t img_uuid;
181*4d495c6eSApple OSS Distributions
182*4d495c6eSApple OSS Distributions std::set<std::pair<const char *, const char *> > dedup_entries;
183*4d495c6eSApple OSS Distributions std::set<std::tuple<const char *, const char *, const char *> > dedup_entries_var;
184*4d495c6eSApple OSS Distributions std::set<const char *> dedup_strings;
185*4d495c6eSApple OSS Distributions
186*4d495c6eSApple OSS Distributions struct {
187*4d495c6eSApple OSS Distributions size_t uniq_structs = 0;
188*4d495c6eSApple OSS Distributions size_t uniq_structs_var = 0;
189*4d495c6eSApple OSS Distributions size_t names_sz = 0;
190*4d495c6eSApple OSS Distributions size_t sig_sz = 0;
191*4d495c6eSApple OSS Distributions } stats;
192*4d495c6eSApple OSS Distributions
193*4d495c6eSApple OSS Distributions void
dump_types(const char * indent)194*4d495c6eSApple OSS Distributions dump_types(const char *indent)
195*4d495c6eSApple OSS Distributions {
196*4d495c6eSApple OSS Distributions const char *sep = "\n";
197*4d495c6eSApple OSS Distributions
198*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
199*4d495c6eSApple OSS Distributions std::cout << ",\n" << indent << " \"fixed\": [";
200*4d495c6eSApple OSS Distributions }
201*4d495c6eSApple OSS Distributions
202*4d495c6eSApple OSS Distributions for (auto &ktv : sec_types->contents) {
203*4d495c6eSApple OSS Distributions const char *name = decode_string(*sec_cstring, ktv.kt_zv.zv_name);
204*4d495c6eSApple OSS Distributions const char *sig = decode_string(*sec_cstring, ktv.kt_signature);
205*4d495c6eSApple OSS Distributions
206*4d495c6eSApple OSS Distributions /* Only output the equal entries (same name/signature) once */
207*4d495c6eSApple OSS Distributions if (!dedup_entries.insert(std::make_tuple(name, sig)).second) {
208*4d495c6eSApple OSS Distributions continue;
209*4d495c6eSApple OSS Distributions }
210*4d495c6eSApple OSS Distributions
211*4d495c6eSApple OSS Distributions if (ktv.kt_flags & KT_DATA_ONLY) {
212*4d495c6eSApple OSS Distributions sig = "data";
213*4d495c6eSApple OSS Distributions }
214*4d495c6eSApple OSS Distributions if (dedup_strings.insert(name).second) {
215*4d495c6eSApple OSS Distributions stats.names_sz += strlen(name) + 1;
216*4d495c6eSApple OSS Distributions }
217*4d495c6eSApple OSS Distributions if (dedup_strings.insert(sig).second) {
218*4d495c6eSApple OSS Distributions stats.sig_sz += strlen(sig) + 1;
219*4d495c6eSApple OSS Distributions }
220*4d495c6eSApple OSS Distributions
221*4d495c6eSApple OSS Distributions stats.uniq_structs++;
222*4d495c6eSApple OSS Distributions if (out_fmt != out_fmt_type::STRUCT) {
223*4d495c6eSApple OSS Distributions name += strlen("site.");
224*4d495c6eSApple OSS Distributions }
225*4d495c6eSApple OSS Distributions
226*4d495c6eSApple OSS Distributions switch (out_fmt) {
227*4d495c6eSApple OSS Distributions case out_fmt_type::SIMPLE:
228*4d495c6eSApple OSS Distributions std::cout << indent << name << " [" << sig << "]\n";
229*4d495c6eSApple OSS Distributions break;
230*4d495c6eSApple OSS Distributions case out_fmt_type::JSON:
231*4d495c6eSApple OSS Distributions std::cout << sep << indent
232*4d495c6eSApple OSS Distributions << " { \"name\": \"" << name << "\", "
233*4d495c6eSApple OSS Distributions << "\"size\": " << ktv.kt_size << ", "
234*4d495c6eSApple OSS Distributions << "\"sig\": \"" << sig << '"'
235*4d495c6eSApple OSS Distributions << " }";
236*4d495c6eSApple OSS Distributions sep = ",\n";
237*4d495c6eSApple OSS Distributions break;
238*4d495c6eSApple OSS Distributions case out_fmt_type::STRUCT: {
239*4d495c6eSApple OSS Distributions /* Make a copy and fill in the pointers to the cstring section */
240*4d495c6eSApple OSS Distributions kalloc_type_view printable_view = ktv;
241*4d495c6eSApple OSS Distributions printable_view.kt_zv.zv_name = name;
242*4d495c6eSApple OSS Distributions printable_view.kt_signature = sig;
243*4d495c6eSApple OSS Distributions __builtin_dump_struct(&printable_view, &printf_with_indent, indent);
244*4d495c6eSApple OSS Distributions } break;
245*4d495c6eSApple OSS Distributions case out_fmt_type::STATS:
246*4d495c6eSApple OSS Distributions break;
247*4d495c6eSApple OSS Distributions }
248*4d495c6eSApple OSS Distributions }
249*4d495c6eSApple OSS Distributions
250*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
251*4d495c6eSApple OSS Distributions std::cout << std::endl << indent << " ]";
252*4d495c6eSApple OSS Distributions }
253*4d495c6eSApple OSS Distributions }
254*4d495c6eSApple OSS Distributions
255*4d495c6eSApple OSS Distributions void
dump_types_var(const char * indent)256*4d495c6eSApple OSS Distributions dump_types_var(const char *indent)
257*4d495c6eSApple OSS Distributions {
258*4d495c6eSApple OSS Distributions const char *sep = "\n";
259*4d495c6eSApple OSS Distributions
260*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
261*4d495c6eSApple OSS Distributions std::cout << ",\n" << indent << " \"var\": [";
262*4d495c6eSApple OSS Distributions }
263*4d495c6eSApple OSS Distributions
264*4d495c6eSApple OSS Distributions for (auto &ktv : sec_types_var->contents) {
265*4d495c6eSApple OSS Distributions const char *name = decode_string(*sec_cstring, ktv.kt_name);
266*4d495c6eSApple OSS Distributions const char *sig_hdr = decode_string(*sec_cstring, ktv.kt_sig_hdr);
267*4d495c6eSApple OSS Distributions const char *sig_type = decode_string(*sec_cstring, ktv.kt_sig_type);
268*4d495c6eSApple OSS Distributions
269*4d495c6eSApple OSS Distributions /* Only output the equal entries (same name/signature) once */
270*4d495c6eSApple OSS Distributions if (!dedup_entries_var.insert(std::make_tuple(name, sig_hdr, sig_type)).second) {
271*4d495c6eSApple OSS Distributions continue;
272*4d495c6eSApple OSS Distributions }
273*4d495c6eSApple OSS Distributions
274*4d495c6eSApple OSS Distributions if (dedup_strings.insert(name).second) {
275*4d495c6eSApple OSS Distributions stats.names_sz += strlen(name) + 1;
276*4d495c6eSApple OSS Distributions }
277*4d495c6eSApple OSS Distributions if (sig_hdr && dedup_strings.insert(sig_hdr).second) {
278*4d495c6eSApple OSS Distributions stats.sig_sz += strlen(sig_hdr) + 1;
279*4d495c6eSApple OSS Distributions }
280*4d495c6eSApple OSS Distributions if (dedup_strings.insert(sig_type).second) {
281*4d495c6eSApple OSS Distributions stats.sig_sz += strlen(sig_type) + 1;
282*4d495c6eSApple OSS Distributions }
283*4d495c6eSApple OSS Distributions
284*4d495c6eSApple OSS Distributions if (ktv.kt_flags & KT_DATA_ONLY) {
285*4d495c6eSApple OSS Distributions sig_type = "data";
286*4d495c6eSApple OSS Distributions if (ktv.kt_size_hdr) {
287*4d495c6eSApple OSS Distributions sig_hdr = "data";
288*4d495c6eSApple OSS Distributions }
289*4d495c6eSApple OSS Distributions }
290*4d495c6eSApple OSS Distributions stats.uniq_structs_var++;
291*4d495c6eSApple OSS Distributions if (out_fmt != out_fmt_type::STRUCT) {
292*4d495c6eSApple OSS Distributions name += strlen("site.");
293*4d495c6eSApple OSS Distributions }
294*4d495c6eSApple OSS Distributions
295*4d495c6eSApple OSS Distributions switch (out_fmt) {
296*4d495c6eSApple OSS Distributions case out_fmt_type::SIMPLE:
297*4d495c6eSApple OSS Distributions if (sig_hdr) {
298*4d495c6eSApple OSS Distributions std::cout << indent << name
299*4d495c6eSApple OSS Distributions << " [" << sig_hdr << ", " << sig_type << "]\n";
300*4d495c6eSApple OSS Distributions } else {
301*4d495c6eSApple OSS Distributions std::cout << indent << name
302*4d495c6eSApple OSS Distributions << " [, " << sig_type << "]\n";
303*4d495c6eSApple OSS Distributions }
304*4d495c6eSApple OSS Distributions break;
305*4d495c6eSApple OSS Distributions case out_fmt_type::JSON:
306*4d495c6eSApple OSS Distributions std::cout << sep << indent
307*4d495c6eSApple OSS Distributions << " { \"name\": \"" << name << "\", ";
308*4d495c6eSApple OSS Distributions if (sig_hdr) {
309*4d495c6eSApple OSS Distributions std::cout << "\"size_hdr\": " << ktv.kt_size_hdr << ", "
310*4d495c6eSApple OSS Distributions << "\"sig_hdr\": \"" << sig_hdr << "\", ";
311*4d495c6eSApple OSS Distributions }
312*4d495c6eSApple OSS Distributions std::cout << "\"size_type\": " << ktv.kt_size_type << ", "
313*4d495c6eSApple OSS Distributions << "\"sig_type\": \"" << sig_type << '"'
314*4d495c6eSApple OSS Distributions << " }";
315*4d495c6eSApple OSS Distributions sep = ",\n";
316*4d495c6eSApple OSS Distributions break;
317*4d495c6eSApple OSS Distributions case out_fmt_type::STRUCT: {
318*4d495c6eSApple OSS Distributions /* Make a copy and fill in the pointers to the cstring section */
319*4d495c6eSApple OSS Distributions kalloc_type_var_view printable_view = ktv;
320*4d495c6eSApple OSS Distributions printable_view.kt_name = name;
321*4d495c6eSApple OSS Distributions printable_view.kt_sig_hdr = sig_hdr;
322*4d495c6eSApple OSS Distributions printable_view.kt_sig_type = sig_type;
323*4d495c6eSApple OSS Distributions __builtin_dump_struct(&printable_view, &printf_with_indent, indent);
324*4d495c6eSApple OSS Distributions } break;
325*4d495c6eSApple OSS Distributions case out_fmt_type::STATS:
326*4d495c6eSApple OSS Distributions break;
327*4d495c6eSApple OSS Distributions }
328*4d495c6eSApple OSS Distributions }
329*4d495c6eSApple OSS Distributions
330*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
331*4d495c6eSApple OSS Distributions std::cout << std::endl << indent << " ]";
332*4d495c6eSApple OSS Distributions }
333*4d495c6eSApple OSS Distributions }
334*4d495c6eSApple OSS Distributions
335*4d495c6eSApple OSS Distributions const mach_header_64 *
mh_hdr() const336*4d495c6eSApple OSS Distributions mh_hdr() const
337*4d495c6eSApple OSS Distributions {
338*4d495c6eSApple OSS Distributions return reinterpret_cast<const mach_header_64 *>(slice_contents.data() + slice_mh_offs);
339*4d495c6eSApple OSS Distributions }
340*4d495c6eSApple OSS Distributions
341*4d495c6eSApple OSS Distributions public:
image(std::span<uint8_t> contents,size_t mh_offs=0)342*4d495c6eSApple OSS Distributions image(std::span<uint8_t> contents, size_t mh_offs = 0)
343*4d495c6eSApple OSS Distributions : slice_contents{contents}, slice_mh_offs{mh_offs}
344*4d495c6eSApple OSS Distributions {
345*4d495c6eSApple OSS Distributions auto *hdr = mh_hdr();
346*4d495c6eSApple OSS Distributions std::span<uint8_t> commands = contents.subspan(mh_offs + sizeof(*hdr));
347*4d495c6eSApple OSS Distributions
348*4d495c6eSApple OSS Distributions assert(hdr->magic == MH_MAGIC_64);
349*4d495c6eSApple OSS Distributions
350*4d495c6eSApple OSS Distributions for (size_t i = 0; i < hdr->ncmds; i++) {
351*4d495c6eSApple OSS Distributions auto *cmd = reinterpret_cast<const load_command *>(commands.data());
352*4d495c6eSApple OSS Distributions
353*4d495c6eSApple OSS Distributions commands = commands.subspan(cmd->cmdsize);
354*4d495c6eSApple OSS Distributions
355*4d495c6eSApple OSS Distributions switch (cmd->cmd) {
356*4d495c6eSApple OSS Distributions case LC_SEGMENT_64:
357*4d495c6eSApple OSS Distributions break;
358*4d495c6eSApple OSS Distributions case LC_UUID:
359*4d495c6eSApple OSS Distributions uuid_copy(img_uuid, reinterpret_cast<const uuid_command *>(cmd)->uuid);
360*4d495c6eSApple OSS Distributions continue;
361*4d495c6eSApple OSS Distributions default:
362*4d495c6eSApple OSS Distributions continue;
363*4d495c6eSApple OSS Distributions }
364*4d495c6eSApple OSS Distributions
365*4d495c6eSApple OSS Distributions auto *seg_cmd = reinterpret_cast<const segment_command_64 *>(cmd);
366*4d495c6eSApple OSS Distributions const std::span<section_64> sections((section_64 *)(seg_cmd + 1), seg_cmd->nsects);
367*4d495c6eSApple OSS Distributions
368*4d495c6eSApple OSS Distributions for (auto &sec : sections) {
369*4d495c6eSApple OSS Distributions std::string_view segname(sec.segname);
370*4d495c6eSApple OSS Distributions std::string_view sectname(sec.sectname);
371*4d495c6eSApple OSS Distributions
372*4d495c6eSApple OSS Distributions if (sectname == "__kalloc_type") {
373*4d495c6eSApple OSS Distributions assert(!sec_types && "Multiple __kalloc_type sections?");
374*4d495c6eSApple OSS Distributions sec_types = macho_section<kalloc_type_view>(sec, slice_contents);
375*4d495c6eSApple OSS Distributions assert(sec.size % sec_types->elem_size() == 0 &&
376*4d495c6eSApple OSS Distributions "Check the definition of kalloc_type_view");
377*4d495c6eSApple OSS Distributions } else if (sectname == "__kalloc_var") {
378*4d495c6eSApple OSS Distributions assert(!sec_types_var && "Multiple __kalloc_var sections?");
379*4d495c6eSApple OSS Distributions sec_types_var = macho_section<kalloc_type_var_view>(sec, slice_contents);
380*4d495c6eSApple OSS Distributions assert(sec.size % sec_types_var->elem_size() == 0 &&
381*4d495c6eSApple OSS Distributions "Check the definition of kalloc_type_var_view");
382*4d495c6eSApple OSS Distributions } else if (segname == "__TEXT" && sectname == "__cstring") {
383*4d495c6eSApple OSS Distributions assert(!sec_cstring && "Multiple __kalloc_var sections?");
384*4d495c6eSApple OSS Distributions sec_cstring = macho_section<char>(sec, slice_contents);
385*4d495c6eSApple OSS Distributions }
386*4d495c6eSApple OSS Distributions }
387*4d495c6eSApple OSS Distributions }
388*4d495c6eSApple OSS Distributions }
389*4d495c6eSApple OSS Distributions
390*4d495c6eSApple OSS Distributions ~image() = default;
391*4d495c6eSApple OSS Distributions
392*4d495c6eSApple OSS Distributions std::string
uuid() const393*4d495c6eSApple OSS Distributions uuid() const
394*4d495c6eSApple OSS Distributions {
395*4d495c6eSApple OSS Distributions uuid_string_t to_str;
396*4d495c6eSApple OSS Distributions uuid_unparse_upper(img_uuid, to_str);
397*4d495c6eSApple OSS Distributions return std::string{to_str};
398*4d495c6eSApple OSS Distributions }
399*4d495c6eSApple OSS Distributions
400*4d495c6eSApple OSS Distributions const char *
slice() const401*4d495c6eSApple OSS Distributions slice() const
402*4d495c6eSApple OSS Distributions {
403*4d495c6eSApple OSS Distributions auto *hdr = mh_hdr();
404*4d495c6eSApple OSS Distributions cpu_type_t cpu;
405*4d495c6eSApple OSS Distributions cpu_subtype_t sub;
406*4d495c6eSApple OSS Distributions
407*4d495c6eSApple OSS Distributions if (hdr->magic == MH_CIGAM_64) {
408*4d495c6eSApple OSS Distributions cpu = OSSwapInt32(hdr->cputype);
409*4d495c6eSApple OSS Distributions sub = OSSwapInt32(hdr->cpusubtype & CPU_SUBTYPE_MASK);
410*4d495c6eSApple OSS Distributions } else {
411*4d495c6eSApple OSS Distributions cpu = hdr->cputype;
412*4d495c6eSApple OSS Distributions sub = hdr->cpusubtype & OSSwapInt32(CPU_SUBTYPE_MASK);
413*4d495c6eSApple OSS Distributions }
414*4d495c6eSApple OSS Distributions
415*4d495c6eSApple OSS Distributions if (cpu == CPU_TYPE_ARM64) {
416*4d495c6eSApple OSS Distributions if (sub == CPU_SUBTYPE_ARM64E) {
417*4d495c6eSApple OSS Distributions return "arm64e";
418*4d495c6eSApple OSS Distributions }
419*4d495c6eSApple OSS Distributions return "arm64";
420*4d495c6eSApple OSS Distributions }
421*4d495c6eSApple OSS Distributions
422*4d495c6eSApple OSS Distributions /* other slices unsupported for now */
423*4d495c6eSApple OSS Distributions return nullptr;
424*4d495c6eSApple OSS Distributions }
425*4d495c6eSApple OSS Distributions
426*4d495c6eSApple OSS Distributions void
dump(const std::string & imgname,const char * indent="")427*4d495c6eSApple OSS Distributions dump(const std::string &imgname, const char *indent = "")
428*4d495c6eSApple OSS Distributions {
429*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
430*4d495c6eSApple OSS Distributions std::cout << indent << "{\n"
431*4d495c6eSApple OSS Distributions << indent << " \"image\": \"" << imgname << "\",\n"
432*4d495c6eSApple OSS Distributions << indent << " \"slice\": \"" << slice() << "\",\n"
433*4d495c6eSApple OSS Distributions << indent << " \"uuid\": \"" << uuid() << '"';
434*4d495c6eSApple OSS Distributions } else {
435*4d495c6eSApple OSS Distributions std::cout << imgname << " (" << slice() << ", " << uuid() << ")\n";
436*4d495c6eSApple OSS Distributions }
437*4d495c6eSApple OSS Distributions
438*4d495c6eSApple OSS Distributions if (sec_types) {
439*4d495c6eSApple OSS Distributions dump_types(indent);
440*4d495c6eSApple OSS Distributions }
441*4d495c6eSApple OSS Distributions
442*4d495c6eSApple OSS Distributions if (sec_types_var) {
443*4d495c6eSApple OSS Distributions dump_types_var(indent);
444*4d495c6eSApple OSS Distributions }
445*4d495c6eSApple OSS Distributions
446*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
447*4d495c6eSApple OSS Distributions std::cout << std::endl << indent << "}";
448*4d495c6eSApple OSS Distributions }
449*4d495c6eSApple OSS Distributions
450*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::STATS) {
451*4d495c6eSApple OSS Distributions if (auto &sec = *sec_types; sec_types) {
452*4d495c6eSApple OSS Distributions auto ucount = stats.uniq_structs;
453*4d495c6eSApple OSS Distributions auto usize = ucount * sec.elem_size();
454*4d495c6eSApple OSS Distributions
455*4d495c6eSApple OSS Distributions std::cout << indent << "__kalloc_type: " << std::endl;
456*4d495c6eSApple OSS Distributions std::cout << indent << " total structs: " << sec.elem_count() << std::endl;
457*4d495c6eSApple OSS Distributions std::cout << indent << " unique structs: " << ucount << std::endl;
458*4d495c6eSApple OSS Distributions std::cout << indent << " total size: " << sec.section.size << std::endl;
459*4d495c6eSApple OSS Distributions std::cout << indent << " unique size: " << usize << std::endl;
460*4d495c6eSApple OSS Distributions }
461*4d495c6eSApple OSS Distributions if (auto &sec = *sec_types_var; sec_types_var) {
462*4d495c6eSApple OSS Distributions auto ucount = stats.uniq_structs_var;
463*4d495c6eSApple OSS Distributions auto usize = ucount * sec.elem_size();
464*4d495c6eSApple OSS Distributions
465*4d495c6eSApple OSS Distributions std::cout << indent << "__kalloc_var: " << std::endl;
466*4d495c6eSApple OSS Distributions std::cout << indent << " total structs: " << sec.elem_count() << std::endl;
467*4d495c6eSApple OSS Distributions std::cout << indent << " unique structs: " << ucount << std::endl;
468*4d495c6eSApple OSS Distributions std::cout << indent << " total size: " << sec.section.size << std::endl;
469*4d495c6eSApple OSS Distributions std::cout << indent << " unique size: " << usize << std::endl;
470*4d495c6eSApple OSS Distributions }
471*4d495c6eSApple OSS Distributions std::cout << indent << "names strings: " << stats.names_sz << std::endl;
472*4d495c6eSApple OSS Distributions std::cout << indent << "signatures strings: " << stats.sig_sz << std::endl;
473*4d495c6eSApple OSS Distributions }
474*4d495c6eSApple OSS Distributions
475*4d495c6eSApple OSS Distributions stats = {};
476*4d495c6eSApple OSS Distributions dedup_entries.clear();
477*4d495c6eSApple OSS Distributions dedup_entries_var.clear();
478*4d495c6eSApple OSS Distributions dedup_strings.clear();
479*4d495c6eSApple OSS Distributions }
480*4d495c6eSApple OSS Distributions };
481*4d495c6eSApple OSS Distributions
482*4d495c6eSApple OSS Distributions static int
do_simple_macho(const std::string filename,std::span<uint8_t> contents)483*4d495c6eSApple OSS Distributions do_simple_macho(const std::string filename, std::span<uint8_t> contents)
484*4d495c6eSApple OSS Distributions {
485*4d495c6eSApple OSS Distributions image img{contents};
486*4d495c6eSApple OSS Distributions img.dump(filename);
487*4d495c6eSApple OSS Distributions return 0;
488*4d495c6eSApple OSS Distributions }
489*4d495c6eSApple OSS Distributions
490*4d495c6eSApple OSS Distributions static int
do_fat_macho(const std::string filename,std::span<uint8_t> contents)491*4d495c6eSApple OSS Distributions do_fat_macho(const std::string filename, std::span<uint8_t> contents)
492*4d495c6eSApple OSS Distributions {
493*4d495c6eSApple OSS Distributions fat_header *fhdr = reinterpret_cast<fat_header *>(contents.data());
494*4d495c6eSApple OSS Distributions std::span<fat_arch> fat_archs(
495*4d495c6eSApple OSS Distributions reinterpret_cast<fat_arch *>(&contents[sizeof(fat_header)]),
496*4d495c6eSApple OSS Distributions OSSwapInt32(fhdr->nfat_arch));
497*4d495c6eSApple OSS Distributions const char *sep = "\n";
498*4d495c6eSApple OSS Distributions
499*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
500*4d495c6eSApple OSS Distributions std::cout << "[";
501*4d495c6eSApple OSS Distributions }
502*4d495c6eSApple OSS Distributions
503*4d495c6eSApple OSS Distributions for (auto &arch : fat_archs) {
504*4d495c6eSApple OSS Distributions image img{contents.subspan(OSSwapInt32(arch.offset), OSSwapInt32(arch.size))};
505*4d495c6eSApple OSS Distributions
506*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
507*4d495c6eSApple OSS Distributions std::cout << sep;
508*4d495c6eSApple OSS Distributions } else {
509*4d495c6eSApple OSS Distributions std::cout << std::endl;
510*4d495c6eSApple OSS Distributions }
511*4d495c6eSApple OSS Distributions img.dump(filename, " ");
512*4d495c6eSApple OSS Distributions sep = ",\n";
513*4d495c6eSApple OSS Distributions }
514*4d495c6eSApple OSS Distributions
515*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
516*4d495c6eSApple OSS Distributions std::cout << "\n]";
517*4d495c6eSApple OSS Distributions }
518*4d495c6eSApple OSS Distributions
519*4d495c6eSApple OSS Distributions return 0;
520*4d495c6eSApple OSS Distributions }
521*4d495c6eSApple OSS Distributions
522*4d495c6eSApple OSS Distributions static int
do_fileset(std::span<uint8_t> contents)523*4d495c6eSApple OSS Distributions do_fileset(std::span<uint8_t> contents)
524*4d495c6eSApple OSS Distributions {
525*4d495c6eSApple OSS Distributions auto *hdr = reinterpret_cast<const mach_header_64 *>(contents.data());
526*4d495c6eSApple OSS Distributions std::span<uint8_t> commands = contents.subspan(sizeof(*hdr));
527*4d495c6eSApple OSS Distributions const char *sep = "\n";
528*4d495c6eSApple OSS Distributions
529*4d495c6eSApple OSS Distributions if (hdr->cputype != CPU_TYPE_ARM64) {
530*4d495c6eSApple OSS Distributions std::cerr << "unsupported cpu type";
531*4d495c6eSApple OSS Distributions return 1;
532*4d495c6eSApple OSS Distributions }
533*4d495c6eSApple OSS Distributions
534*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
535*4d495c6eSApple OSS Distributions std::cout << "[";
536*4d495c6eSApple OSS Distributions }
537*4d495c6eSApple OSS Distributions
538*4d495c6eSApple OSS Distributions for (size_t i = 0; i < hdr->ncmds; i++) {
539*4d495c6eSApple OSS Distributions auto *cmd = reinterpret_cast<const segment_command_64 *>(commands.data());
540*4d495c6eSApple OSS Distributions
541*4d495c6eSApple OSS Distributions commands = commands.subspan(cmd->cmdsize);
542*4d495c6eSApple OSS Distributions
543*4d495c6eSApple OSS Distributions if (cmd->cmd != LC_FILESET_ENTRY) {
544*4d495c6eSApple OSS Distributions continue;
545*4d495c6eSApple OSS Distributions }
546*4d495c6eSApple OSS Distributions
547*4d495c6eSApple OSS Distributions auto *fec = reinterpret_cast<const fileset_entry_command *>(cmd);
548*4d495c6eSApple OSS Distributions const char *name = reinterpret_cast<const char *>(cmd) + fec->entry_id.offset;
549*4d495c6eSApple OSS Distributions image img{contents, fec->fileoff};
550*4d495c6eSApple OSS Distributions
551*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
552*4d495c6eSApple OSS Distributions std::cout << sep;
553*4d495c6eSApple OSS Distributions } else {
554*4d495c6eSApple OSS Distributions std::cout << std::endl;
555*4d495c6eSApple OSS Distributions }
556*4d495c6eSApple OSS Distributions img.dump(name, " ");
557*4d495c6eSApple OSS Distributions sep = ",\n";
558*4d495c6eSApple OSS Distributions }
559*4d495c6eSApple OSS Distributions
560*4d495c6eSApple OSS Distributions if (out_fmt == out_fmt_type::JSON) {
561*4d495c6eSApple OSS Distributions std::cout << "]";
562*4d495c6eSApple OSS Distributions }
563*4d495c6eSApple OSS Distributions
564*4d495c6eSApple OSS Distributions return 0;
565*4d495c6eSApple OSS Distributions }
566*4d495c6eSApple OSS Distributions
567*4d495c6eSApple OSS Distributions void
read_file(std::filesystem::path & path,std::vector<uint8_t> & contents)568*4d495c6eSApple OSS Distributions read_file(std::filesystem::path &path, std::vector<uint8_t> &contents)
569*4d495c6eSApple OSS Distributions {
570*4d495c6eSApple OSS Distributions std::ifstream file(path, std::ifstream::binary);
571*4d495c6eSApple OSS Distributions size_t size(std::filesystem::file_size(path));
572*4d495c6eSApple OSS Distributions
573*4d495c6eSApple OSS Distributions contents.resize(size);
574*4d495c6eSApple OSS Distributions file.read(reinterpret_cast<char *>(contents.data()), size);
575*4d495c6eSApple OSS Distributions file.close();
576*4d495c6eSApple OSS Distributions }
577*4d495c6eSApple OSS Distributions
578*4d495c6eSApple OSS Distributions enum class file_kind {
579*4d495c6eSApple OSS Distributions UNKNOWN,
580*4d495c6eSApple OSS Distributions MACHO,
581*4d495c6eSApple OSS Distributions FAT_MACHO,
582*4d495c6eSApple OSS Distributions FILESET,
583*4d495c6eSApple OSS Distributions IMG4,
584*4d495c6eSApple OSS Distributions };
585*4d495c6eSApple OSS Distributions
586*4d495c6eSApple OSS Distributions static file_kind
recognize_file(const std::vector<uint8_t> & contents)587*4d495c6eSApple OSS Distributions recognize_file(const std::vector<uint8_t> &contents)
588*4d495c6eSApple OSS Distributions {
589*4d495c6eSApple OSS Distributions const mach_header_64 *hdr;
590*4d495c6eSApple OSS Distributions
591*4d495c6eSApple OSS Distributions if (contents.size() < sizeof(mach_header_64)) {
592*4d495c6eSApple OSS Distributions return file_kind::UNKNOWN;
593*4d495c6eSApple OSS Distributions }
594*4d495c6eSApple OSS Distributions
595*4d495c6eSApple OSS Distributions hdr = reinterpret_cast<const mach_header_64 *>(contents.data());
596*4d495c6eSApple OSS Distributions if (hdr->magic == MH_MAGIC_64) {
597*4d495c6eSApple OSS Distributions switch (hdr->filetype) {
598*4d495c6eSApple OSS Distributions case MH_FILESET:
599*4d495c6eSApple OSS Distributions return file_kind::FILESET;
600*4d495c6eSApple OSS Distributions default:
601*4d495c6eSApple OSS Distributions return file_kind::MACHO;
602*4d495c6eSApple OSS Distributions }
603*4d495c6eSApple OSS Distributions }
604*4d495c6eSApple OSS Distributions
605*4d495c6eSApple OSS Distributions if (hdr->magic == FAT_CIGAM) {
606*4d495c6eSApple OSS Distributions return file_kind::FAT_MACHO;
607*4d495c6eSApple OSS Distributions }
608*4d495c6eSApple OSS Distributions
609*4d495c6eSApple OSS Distributions if (memcmp("IM4P", contents.data() + 8, 4) == 0) {
610*4d495c6eSApple OSS Distributions return file_kind::IMG4;
611*4d495c6eSApple OSS Distributions }
612*4d495c6eSApple OSS Distributions
613*4d495c6eSApple OSS Distributions return file_kind::UNKNOWN;
614*4d495c6eSApple OSS Distributions }
615*4d495c6eSApple OSS Distributions
616*4d495c6eSApple OSS Distributions static int
call_cmd_silent(const char * const * args)617*4d495c6eSApple OSS Distributions call_cmd_silent(const char *const *args)
618*4d495c6eSApple OSS Distributions {
619*4d495c6eSApple OSS Distributions posix_spawn_file_actions_t facts;
620*4d495c6eSApple OSS Distributions extern char **environ;
621*4d495c6eSApple OSS Distributions pid_t pid;
622*4d495c6eSApple OSS Distributions int rc;
623*4d495c6eSApple OSS Distributions
624*4d495c6eSApple OSS Distributions posix_spawn_file_actions_init(&facts);
625*4d495c6eSApple OSS Distributions posix_spawn_file_actions_addopen(&facts,
626*4d495c6eSApple OSS Distributions STDIN_FILENO, "/dev/null", O_RDONLY, 0777);
627*4d495c6eSApple OSS Distributions posix_spawn_file_actions_addopen(&facts,
628*4d495c6eSApple OSS Distributions STDOUT_FILENO, "/dev/null", O_WRONLY, 0777);
629*4d495c6eSApple OSS Distributions posix_spawn_file_actions_addopen(&facts,
630*4d495c6eSApple OSS Distributions STDERR_FILENO, "/dev/null", O_WRONLY, 0777);
631*4d495c6eSApple OSS Distributions rc = posix_spawnp(&pid, args[0], &facts, nullptr,
632*4d495c6eSApple OSS Distributions (char *const *)args, environ);
633*4d495c6eSApple OSS Distributions posix_spawn_file_actions_destroy(&facts);
634*4d495c6eSApple OSS Distributions
635*4d495c6eSApple OSS Distributions if (rc != 0) {
636*4d495c6eSApple OSS Distributions return 1;
637*4d495c6eSApple OSS Distributions }
638*4d495c6eSApple OSS Distributions
639*4d495c6eSApple OSS Distributions waitpid(pid, &rc, 0);
640*4d495c6eSApple OSS Distributions if (!WIFEXITED(rc) || WEXITSTATUS(rc)) {
641*4d495c6eSApple OSS Distributions return 1;
642*4d495c6eSApple OSS Distributions }
643*4d495c6eSApple OSS Distributions
644*4d495c6eSApple OSS Distributions return 0;
645*4d495c6eSApple OSS Distributions }
646*4d495c6eSApple OSS Distributions
647*4d495c6eSApple OSS Distributions static int
do_file(const std::filesystem::path & path,std::vector<uint8_t> & contents)648*4d495c6eSApple OSS Distributions do_file(const std::filesystem::path &path, std::vector<uint8_t> &contents)
649*4d495c6eSApple OSS Distributions {
650*4d495c6eSApple OSS Distributions int status = 0;
651*4d495c6eSApple OSS Distributions
652*4d495c6eSApple OSS Distributions switch (recognize_file(contents)) {
653*4d495c6eSApple OSS Distributions case file_kind::MACHO:
654*4d495c6eSApple OSS Distributions return do_simple_macho(path.filename().string(), contents);
655*4d495c6eSApple OSS Distributions case file_kind::FAT_MACHO:
656*4d495c6eSApple OSS Distributions return do_fat_macho(path.filename().string(), contents);
657*4d495c6eSApple OSS Distributions case file_kind::FILESET:
658*4d495c6eSApple OSS Distributions return do_fileset(contents);
659*4d495c6eSApple OSS Distributions case file_kind::IMG4:
660*4d495c6eSApple OSS Distributions break;
661*4d495c6eSApple OSS Distributions case file_kind::UNKNOWN:
662*4d495c6eSApple OSS Distributions std::cerr << "Unsupported file type\n";
663*4d495c6eSApple OSS Distributions return 1;
664*4d495c6eSApple OSS Distributions }
665*4d495c6eSApple OSS Distributions
666*4d495c6eSApple OSS Distributions char tmp_tpl[] = "/tmp/kt-dump.XXXXXX";
667*4d495c6eSApple OSS Distributions char *tmp_dir = mkdtemp(tmp_tpl);
668*4d495c6eSApple OSS Distributions
669*4d495c6eSApple OSS Distributions if (tmp_dir == NULL) {
670*4d495c6eSApple OSS Distributions std::cerr << "Unable to make temporary directory to unpack img4\n";
671*4d495c6eSApple OSS Distributions return 1;
672*4d495c6eSApple OSS Distributions }
673*4d495c6eSApple OSS Distributions
674*4d495c6eSApple OSS Distributions std::filesystem::path compressed_kc{tmp_dir};
675*4d495c6eSApple OSS Distributions std::filesystem::path uncompressed_kc{tmp_dir};
676*4d495c6eSApple OSS Distributions
677*4d495c6eSApple OSS Distributions compressed_kc /= "compressed.kc";
678*4d495c6eSApple OSS Distributions uncompressed_kc /= "uncompressed.kc";
679*4d495c6eSApple OSS Distributions
680*4d495c6eSApple OSS Distributions static const char *const img4args[] = {
681*4d495c6eSApple OSS Distributions "img4utility",
682*4d495c6eSApple OSS Distributions "--copyBinary",
683*4d495c6eSApple OSS Distributions "--input",
684*4d495c6eSApple OSS Distributions path.c_str(),
685*4d495c6eSApple OSS Distributions "--output",
686*4d495c6eSApple OSS Distributions compressed_kc.c_str(),
687*4d495c6eSApple OSS Distributions NULL,
688*4d495c6eSApple OSS Distributions };
689*4d495c6eSApple OSS Distributions
690*4d495c6eSApple OSS Distributions static const char *const ct_args[] = {
691*4d495c6eSApple OSS Distributions "compression_tool",
692*4d495c6eSApple OSS Distributions "-decode",
693*4d495c6eSApple OSS Distributions "-v",
694*4d495c6eSApple OSS Distributions "-v",
695*4d495c6eSApple OSS Distributions "-v",
696*4d495c6eSApple OSS Distributions "-i",
697*4d495c6eSApple OSS Distributions compressed_kc.c_str(),
698*4d495c6eSApple OSS Distributions "-o",
699*4d495c6eSApple OSS Distributions uncompressed_kc.c_str(),
700*4d495c6eSApple OSS Distributions NULL,
701*4d495c6eSApple OSS Distributions };
702*4d495c6eSApple OSS Distributions
703*4d495c6eSApple OSS Distributions if (call_cmd_silent(img4args)) {
704*4d495c6eSApple OSS Distributions std::cerr << "Unable to unpack img4 image\n";
705*4d495c6eSApple OSS Distributions status = 1;
706*4d495c6eSApple OSS Distributions } else if (call_cmd_silent(ct_args)) {
707*4d495c6eSApple OSS Distributions std::cerr << "Unable to decompress KC\n";
708*4d495c6eSApple OSS Distributions status = 1;
709*4d495c6eSApple OSS Distributions } else {
710*4d495c6eSApple OSS Distributions read_file(uncompressed_kc, contents);
711*4d495c6eSApple OSS Distributions }
712*4d495c6eSApple OSS Distributions
713*4d495c6eSApple OSS Distributions removefile_state_t s = removefile_state_alloc();
714*4d495c6eSApple OSS Distributions removefile(tmp_dir, s, REMOVEFILE_RECURSIVE);
715*4d495c6eSApple OSS Distributions removefile_state_free(s);
716*4d495c6eSApple OSS Distributions
717*4d495c6eSApple OSS Distributions return status ?: do_file(path, contents);
718*4d495c6eSApple OSS Distributions }
719*4d495c6eSApple OSS Distributions
720*4d495c6eSApple OSS Distributions int
main(int argc,char const * argv[])721*4d495c6eSApple OSS Distributions main(int argc, char const *argv[])
722*4d495c6eSApple OSS Distributions {
723*4d495c6eSApple OSS Distributions if (argc != 2 && argc != 4) {
724*4d495c6eSApple OSS Distributions std::cout << "Usage: " << argv[0]
725*4d495c6eSApple OSS Distributions << " [-f <simple|json|struct|stats>] <mach-o>\n";
726*4d495c6eSApple OSS Distributions return 1;
727*4d495c6eSApple OSS Distributions }
728*4d495c6eSApple OSS Distributions
729*4d495c6eSApple OSS Distributions std::string path_arg;
730*4d495c6eSApple OSS Distributions
731*4d495c6eSApple OSS Distributions /* Parse command line args */
732*4d495c6eSApple OSS Distributions for (int i = 1; i < argc; i++) {
733*4d495c6eSApple OSS Distributions std::string arg(argv[i]);
734*4d495c6eSApple OSS Distributions if (arg == "-f") {
735*4d495c6eSApple OSS Distributions if (++i == argc) {
736*4d495c6eSApple OSS Distributions std::cerr << "Option " << arg << " requires an argument\n";
737*4d495c6eSApple OSS Distributions return 1;
738*4d495c6eSApple OSS Distributions }
739*4d495c6eSApple OSS Distributions arg = argv[i];
740*4d495c6eSApple OSS Distributions if (arg == "simple") {
741*4d495c6eSApple OSS Distributions out_fmt = out_fmt_type::SIMPLE;
742*4d495c6eSApple OSS Distributions } else if (arg == "json" || arg == "JSON") {
743*4d495c6eSApple OSS Distributions out_fmt = out_fmt_type::JSON;
744*4d495c6eSApple OSS Distributions } else if (arg == "struct") {
745*4d495c6eSApple OSS Distributions out_fmt = out_fmt_type::STRUCT;
746*4d495c6eSApple OSS Distributions } else if (arg == "stats") {
747*4d495c6eSApple OSS Distributions out_fmt = out_fmt_type::STATS;
748*4d495c6eSApple OSS Distributions } else {
749*4d495c6eSApple OSS Distributions std::cerr << "Unknown output format: " << arg << std::endl;
750*4d495c6eSApple OSS Distributions return 1;
751*4d495c6eSApple OSS Distributions }
752*4d495c6eSApple OSS Distributions } else {
753*4d495c6eSApple OSS Distributions /* Read the file specified as a positional arg */
754*4d495c6eSApple OSS Distributions path_arg = arg;
755*4d495c6eSApple OSS Distributions }
756*4d495c6eSApple OSS Distributions }
757*4d495c6eSApple OSS Distributions
758*4d495c6eSApple OSS Distributions if (path_arg.length() == 0) {
759*4d495c6eSApple OSS Distributions std::cerr << "no file specified\n";
760*4d495c6eSApple OSS Distributions return 1;
761*4d495c6eSApple OSS Distributions }
762*4d495c6eSApple OSS Distributions
763*4d495c6eSApple OSS Distributions std::filesystem::path path(path_arg);
764*4d495c6eSApple OSS Distributions std::vector<uint8_t> contents;
765*4d495c6eSApple OSS Distributions
766*4d495c6eSApple OSS Distributions read_file(path, contents);
767*4d495c6eSApple OSS Distributions return do_file(path, contents);
768*4d495c6eSApple OSS Distributions }
769