]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kdp/ml/i386/kdp_vm.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / osfmk / kdp / ml / i386 / kdp_vm.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28#include <mach/mach_types.h>
29#include <mach/vm_attributes.h>
30#include <mach/vm_param.h>
9bccf70c 31#include <libsa/types.h>
0c530ab8
A
32
33#include <vm/vm_map.h>
34#include <i386/pmap.h>
35
36#include <kdp/kdp_core.h>
37#include <kdp/kdp_internal.h>
38#include <mach-o/loader.h>
39#include <mach/vm_map.h>
40#include <mach/vm_statistics.h>
41#include <mach/thread_status.h>
42#include <i386/thread.h>
43
44#include <vm/vm_protos.h>
45#include <vm/vm_kern.h>
46
0c530ab8 47extern vm_offset_t sectTEXTB, sectDATAB, sectLINKB, sectPRELINKB;
b0d623f7 48extern unsigned long sectSizeTEXT, sectSizeDATA, sectSizeLINK, sectSizePRELINK;
0c530ab8
A
49
50int kern_dump(void);
51int kdp_dump_trap(int type, x86_saved_state32_t *regs);
52
53typedef struct {
54 int flavor; /* the number for this flavor */
55 mach_msg_type_number_t count; /* count of ints in this flavor */
56} mythread_state_flavor_t;
57
58static mythread_state_flavor_t thread_flavor_array [] = {
59 {x86_THREAD_STATE32, x86_THREAD_STATE32_COUNT}
60};
61
62static int kdp_mynum_flavors = 1;
63static int MAX_TSTATE_FLAVORS = 1;
64
65typedef struct {
66 vm_offset_t header;
67 int hoffset;
68 mythread_state_flavor_t *flavors;
69 int tstate_size;
70} tir_t;
71
72char command_buffer[512];
73
0c530ab8
A
74static void
75kern_collectth_state(thread_t thread, tir_t *t)
4452a7af 76{
0c530ab8
A
77 vm_offset_t header;
78 int hoffset, i ;
79 mythread_state_flavor_t *flavors;
80 struct thread_command *tc;
81 /*
82 * Fill in thread command structure.
83 */
84 header = t->header;
85 hoffset = t->hoffset;
86 flavors = t->flavors;
87
88 tc = (struct thread_command *) (header + hoffset);
89 tc->cmd = LC_THREAD;
90 tc->cmdsize = sizeof(struct thread_command) + t->tstate_size;
91 hoffset += sizeof(struct thread_command);
92 /*
93 * Follow with a struct thread_state_flavor and
94 * the appropriate thread state struct for each
95 * thread state flavor.
96 */
97 for (i = 0; i < kdp_mynum_flavors; i++) {
98 *(mythread_state_flavor_t *)(header+hoffset) =
99 flavors[i];
100 hoffset += sizeof(mythread_state_flavor_t);
101 /* Locate and obtain the non-volatile register context
102 * for this kernel thread. This should ideally be
103 * encapsulated in machine_thread_get_kern_state()
104 * but that routine appears to have been co-opted
105 * by CHUD to obtain pre-interrupt state.
106 */
107 if (flavors[i].flavor == x86_THREAD_STATE32) {
108 x86_thread_state32_t *tstate = (x86_thread_state32_t *) (header + hoffset);
109 vm_offset_t kstack;
110 bzero(tstate, x86_THREAD_STATE32_COUNT * sizeof(int));
111 if ((kstack = thread->kernel_stack) != 0){
b0d623f7 112 struct x86_kernel_state *iks = STACK_IKS(kstack);
0c530ab8
A
113 tstate->ebx = iks->k_ebx;
114 tstate->esp = iks->k_esp;
115 tstate->ebp = iks->k_ebp;
116 tstate->edi = iks->k_edi;
117 tstate->esi = iks->k_esi;
118 tstate->eip = iks->k_eip;
119 }
120 }
121 else if (machine_thread_get_kern_state(thread,
122 flavors[i].flavor, (thread_state_t) (header+hoffset),
123 &flavors[i].count) != KERN_SUCCESS)
124 printf ("Failure in machine_thread_get_kern_state()\n");
125 hoffset += flavors[i].count*sizeof(int);
126 }
127
128 t->hoffset = hoffset;
129}
130
131/* Intended to be called from the kernel trap handler if an unrecoverable fault
132 * occurs during a crashdump (which shouldn't happen since we validate mappings
133 * and so on). This should be reworked to attempt some form of recovery.
134 */
135int
136kdp_dump_trap(
137 int type,
138 __unused x86_saved_state32_t *saved_state)
139{
140 printf ("An unexpected trap (type %d) occurred during the system dump, terminating.\n", type);
141 kdp_send_crashdump_pkt (KDP_EOF, NULL, 0, ((void *) 0));
142 abort_panic_transfer();
143 kdp_flag &= ~KDP_PANIC_DUMP_ENABLED;
144 kdp_flag &= ~PANIC_CORE_ON_NMI;
145 kdp_flag &= ~PANIC_LOG_DUMP;
146
147 kdp_reset();
148
149 kdp_raise_exception(EXC_BAD_ACCESS, 0, 0, kdp.saved_state);
150 return( 0 );
151}
152
153int
154kern_dump(void)
155{
156 vm_map_t map;
157 unsigned int thread_count, segment_count;
158 unsigned int command_size = 0, header_size = 0, tstate_size = 0;
159 unsigned int hoffset = 0, foffset = 0, nfoffset = 0, vmoffset = 0;
160 unsigned int max_header_size = 0;
161 vm_offset_t header;
162 struct mach_header *mh;
163 struct segment_command *sc;
164 vm_size_t size;
165 vm_prot_t prot = 0;
166 vm_prot_t maxprot = 0;
167 vm_inherit_t inherit = 0;
168 mythread_state_flavor_t flavors[MAX_TSTATE_FLAVORS];
169 vm_size_t nflavors;
170 vm_size_t i;
171 uint32_t nesting_depth = 0;
172 kern_return_t kret = 0;
173 struct vm_region_submap_info_64 vbr;
174 mach_msg_type_number_t vbrcount = 0;
175 tir_t tir1;
176
177 int error = 0;
178 int panic_error = 0;
179 unsigned int txstart = 0;
180 unsigned int mach_section_count = 4;
181 unsigned int num_sects_txed = 0;
182
183 map = kernel_map;
184
0c530ab8
A
185 thread_count = 1;
186 segment_count = get_vmmap_entries(map);
187
188 printf("Kernel map has %d entries\n", segment_count);
189
190 nflavors = kdp_mynum_flavors;
191 bcopy((char *)thread_flavor_array,(char *) flavors,sizeof(thread_flavor_array));
192
193 for (i = 0; i < nflavors; i++)
194 tstate_size += sizeof(mythread_state_flavor_t) +
195 (flavors[i].count * sizeof(int));
196
197 command_size = (segment_count + mach_section_count) *
198 sizeof(struct segment_command) +
199 thread_count * sizeof(struct thread_command) +
200 tstate_size * thread_count;
201
202 header_size = command_size + sizeof(struct mach_header);
203 header = (vm_offset_t) command_buffer;
204
205 /*
206 * Set up Mach-O header for currently executing 32 bit kernel.
207 */
208 printf ("Generated Mach-O header size was %d\n", header_size);
209
210 mh = (struct mach_header *) header;
211 mh->magic = MH_MAGIC;
212 mh->cputype = cpu_type();
213 mh->cpusubtype = cpu_subtype();
214 mh->filetype = MH_CORE;
215 mh->ncmds = segment_count + thread_count + mach_section_count;
216 mh->sizeofcmds = command_size;
217 mh->flags = 0;
218
219 hoffset = sizeof(struct mach_header); /* offset into header */
220 foffset = round_page_32(header_size); /* offset into file */
221 /* Padding */
222 if ((foffset - header_size) < (4*sizeof(struct segment_command))) {
223 foffset += ((4*sizeof(struct segment_command)) - (foffset-header_size));
224 }
225
226 max_header_size = foffset;
227
228 vmoffset = VM_MIN_ADDRESS; /* offset into VM */
229
230 /* Transmit the Mach-O MH_CORE header, and seek forward past the
231 * area reserved for the segment and thread commands
232 * to begin data transmission
233 */
234
235 if ((panic_error = kdp_send_crashdump_pkt (KDP_SEEK, NULL, sizeof(nfoffset) , &nfoffset)) < 0) {
236 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
237 error = panic_error;
238 goto out;
239 }
240
241 if ((panic_error = kdp_send_crashdump_data (KDP_DATA, NULL, sizeof(struct mach_header), (caddr_t) mh) < 0)) {
242 printf ("kdp_send_crashdump_data failed with error %d\n", panic_error);
243 error = panic_error;
244 goto out;
245 }
246
247 if ((panic_error = kdp_send_crashdump_pkt (KDP_SEEK, NULL, sizeof(foffset) , &foffset) < 0)) {
248 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
249 error = panic_error;
250 goto out;
251 }
252 printf ("Transmitting kernel state, please wait: ");
253
254 while ((segment_count > 0) || (kret == KERN_SUCCESS)){
255 /* Check if we've transmitted all the kernel sections */
256 if (num_sects_txed == mach_section_count) {
257
258 while (1) {
259
260 /*
261 * Get region information for next region.
262 */
263
264 vbrcount = VM_REGION_SUBMAP_INFO_COUNT_64;
265 if((kret = vm_region_recurse_64(map,
266 &vmoffset, &size, &nesting_depth,
267 (vm_region_recurse_info_t)&vbr,
268 &vbrcount)) != KERN_SUCCESS) {
269 break;
270 }
271
272 if(vbr.is_submap) {
273 nesting_depth++;
274 continue;
275 } else {
276 break;
277 }
278 }
279
280 if(kret != KERN_SUCCESS)
281 break;
282
283 prot = vbr.protection;
284 maxprot = vbr.max_protection;
285 inherit = vbr.inheritance;
286 }
287 else
288 {
289 switch (num_sects_txed) {
290 case 0:
291 /* Transmit the kernel text section */
292 vmoffset = sectTEXTB;
293 size = sectSizeTEXT;
294 break;
295 case 1:
296 vmoffset = sectDATAB;
297 size = sectSizeDATA;
298 break;
299 case 2:
300 vmoffset = sectPRELINKB;
301 size = sectSizePRELINK;
302 break;
303 case 3:
304 vmoffset = sectLINKB;
305 size = sectSizeLINK;
306 break;
307 }
308 num_sects_txed++;
309 }
310 /*
311 * Fill in segment command structure.
312 */
313
314 if (hoffset > max_header_size)
315 break;
316 sc = (struct segment_command *) (header);
317 sc->cmd = LC_SEGMENT;
318 sc->cmdsize = sizeof(struct segment_command);
319 sc->segname[0] = 0;
320 sc->vmaddr = vmoffset;
321 sc->vmsize = size;
322 sc->fileoff = foffset;
323 sc->filesize = size;
324 sc->maxprot = maxprot;
325 sc->initprot = prot;
326 sc->nsects = 0;
327
328 if ((panic_error = kdp_send_crashdump_pkt (KDP_SEEK, NULL, sizeof(hoffset) , &hoffset)) < 0) {
329 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
330 error = panic_error;
331 goto out;
332 }
333
334 if ((panic_error = kdp_send_crashdump_data (KDP_DATA, NULL, sizeof(struct segment_command) , (caddr_t) sc)) < 0) {
335 printf ("kdp_send_crashdump_data failed with error %d\n", panic_error);
336 error = panic_error;
337 goto out;
338 }
339
340 /* Do not transmit memory tagged VM_MEMORY_IOKIT - instead,
341 * seek past that region on the server - this creates a
342 * hole in the file.
343 */
344
345 if ((vbr.user_tag != VM_MEMORY_IOKIT)) {
346
347 if ((panic_error = kdp_send_crashdump_pkt (KDP_SEEK, NULL, sizeof(foffset) , &foffset)) < 0) {
348 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
349 error = panic_error;
350 goto out;
351 }
352
353 txstart = vmoffset;
354
355 if ((panic_error = kdp_send_crashdump_data (KDP_DATA, NULL, size, (caddr_t) txstart)) < 0) {
356 printf ("kdp_send_crashdump_data failed with error %d\n", panic_error);
357 error = panic_error;
358 goto out;
359 }
360 }
361
362 hoffset += sizeof(struct segment_command);
363 foffset += size;
364 vmoffset += size;
365 segment_count--;
366 }
367 tir1.header = header;
368 tir1.hoffset = 0;
369 tir1.flavors = flavors;
370 tir1.tstate_size = tstate_size;
371
372 /* Now send out the LC_THREAD load command, with the thread information
373 * for the current activation.
374 * Note that the corefile can contain LC_SEGMENT commands with file
375 * offsets that point past the edge of the corefile, in the event that
376 * the last N VM regions were all I/O mapped or otherwise
377 * non-transferable memory, not followed by a normal VM region;
378 * i.e. there will be no hole that reaches to the end of the core file.
379 */
380 kern_collectth_state (current_thread(), &tir1);
381
382 if ((panic_error = kdp_send_crashdump_pkt (KDP_SEEK, NULL, sizeof(hoffset) , &hoffset)) < 0) {
383 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
384 error = panic_error;
385 goto out;
386 }
387
388 if ((panic_error = kdp_send_crashdump_data (KDP_DATA, NULL, tir1.hoffset , (caddr_t) header)) < 0) {
389 printf ("kdp_send_crashdump_data failed with error %d\n", panic_error);
390 error = panic_error;
391 goto out;
392 }
393
394 /* last packet */
395 if ((panic_error = kdp_send_crashdump_pkt (KDP_EOF, NULL, 0, ((void *) 0))) < 0)
396 {
397 printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error);
398 error = panic_error;
399 goto out;
400 }
401out:
402 return (error);
55e303ae 403}