]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libkvm/kvm_minidump_i386.c
Merge llvm, clang, lld and lldb trunk r300890, and update build glue.
[FreeBSD/FreeBSD.git] / lib / libkvm / kvm_minidump_i386.c
1 /*-
2  * Copyright (c) 2006 Peter Wemm
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 /*
30  * i386 machine dependent routines for kvm and minidumps.
31  */
32
33 #include <sys/param.h>
34 #include <sys/endian.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <kvm.h>
40
41 #include "../../sys/i386/include/minidump.h"
42
43 #include <limits.h>
44
45 #include "kvm_private.h"
46 #include "kvm_i386.h"
47
48 #define i386_round_page(x)      roundup2((kvaddr_t)(x), I386_PAGE_SIZE)
49
50 struct vmstate {
51         struct minidumphdr hdr;
52         void *ptemap;
53 };
54
55 static int
56 _i386_minidump_probe(kvm_t *kd)
57 {
58
59         return (_kvm_probe_elf_kernel(kd, ELFCLASS32, EM_386) &&
60             _kvm_is_minidump(kd));
61 }
62
63 static void
64 _i386_minidump_freevtop(kvm_t *kd)
65 {
66         struct vmstate *vm = kd->vmst;
67
68         free(vm->ptemap);
69         free(vm);
70         kd->vmst = NULL;
71 }
72
73 static int
74 _i386_minidump_initvtop(kvm_t *kd)
75 {
76         struct vmstate *vmst;
77         off_t off, sparse_off;
78
79         vmst = _kvm_malloc(kd, sizeof(*vmst));
80         if (vmst == NULL) {
81                 _kvm_err(kd, kd->program, "cannot allocate vm");
82                 return (-1);
83         }
84         kd->vmst = vmst;
85         if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
86             sizeof(vmst->hdr)) {
87                 _kvm_err(kd, kd->program, "cannot read dump header");
88                 return (-1);
89         }
90         if (strncmp(MINIDUMP_MAGIC, vmst->hdr.magic, sizeof(vmst->hdr.magic)) != 0) {
91                 _kvm_err(kd, kd->program, "not a minidump for this platform");
92                 return (-1);
93         }
94         vmst->hdr.version = le32toh(vmst->hdr.version);
95         if (vmst->hdr.version != MINIDUMP_VERSION) {
96                 _kvm_err(kd, kd->program, "wrong minidump version. expected %d got %d",
97                     MINIDUMP_VERSION, vmst->hdr.version);
98                 return (-1);
99         }
100         vmst->hdr.msgbufsize = le32toh(vmst->hdr.msgbufsize);
101         vmst->hdr.bitmapsize = le32toh(vmst->hdr.bitmapsize);
102         vmst->hdr.ptesize = le32toh(vmst->hdr.ptesize);
103         vmst->hdr.kernbase = le32toh(vmst->hdr.kernbase);
104         vmst->hdr.paemode = le32toh(vmst->hdr.paemode);
105
106         /* Skip header and msgbuf */
107         off = I386_PAGE_SIZE + i386_round_page(vmst->hdr.msgbufsize);
108
109         sparse_off = off + i386_round_page(vmst->hdr.bitmapsize) +
110             i386_round_page(vmst->hdr.ptesize);
111         if (_kvm_pt_init(kd, vmst->hdr.bitmapsize, off, sparse_off,
112             I386_PAGE_SIZE, sizeof(uint32_t)) == -1) {
113                 _kvm_err(kd, kd->program, "cannot load core bitmap");
114                 return (-1);
115         }
116         off += i386_round_page(vmst->hdr.bitmapsize);
117
118         vmst->ptemap = _kvm_malloc(kd, vmst->hdr.ptesize);
119         if (vmst->ptemap == NULL) {
120                 _kvm_err(kd, kd->program, "cannot allocate %d bytes for ptemap", vmst->hdr.ptesize);
121                 return (-1);
122         }
123         if (pread(kd->pmfd, vmst->ptemap, vmst->hdr.ptesize, off) !=
124             (ssize_t)vmst->hdr.ptesize) {
125                 _kvm_err(kd, kd->program, "cannot read %d bytes for ptemap", vmst->hdr.ptesize);
126                 return (-1);
127         }
128         off += i386_round_page(vmst->hdr.ptesize);
129
130         return (0);
131 }
132
133 static int
134 _i386_minidump_vatop_pae(kvm_t *kd, kvaddr_t va, off_t *pa)
135 {
136         struct vmstate *vm;
137         i386_physaddr_pae_t offset;
138         i386_pte_pae_t pte;
139         kvaddr_t pteindex;
140         i386_physaddr_pae_t a;
141         off_t ofs;
142         i386_pte_pae_t *ptemap;
143
144         vm = kd->vmst;
145         ptemap = vm->ptemap;
146         offset = va & I386_PAGE_MASK;
147
148         if (va >= vm->hdr.kernbase) {
149                 pteindex = (va - vm->hdr.kernbase) >> I386_PAGE_SHIFT;
150                 if (pteindex >= vm->hdr.ptesize / sizeof(*ptemap))
151                         goto invalid;
152                 pte = le64toh(ptemap[pteindex]);
153                 if ((pte & I386_PG_V) == 0) {
154                         _kvm_err(kd, kd->program,
155                             "_i386_minidump_vatop_pae: pte not valid");
156                         goto invalid;
157                 }
158                 a = pte & I386_PG_FRAME_PAE;
159                 ofs = _kvm_pt_find(kd, a);
160                 if (ofs == -1) {
161                         _kvm_err(kd, kd->program,
162             "_i386_minidump_vatop_pae: physical address 0x%jx not in minidump",
163                             (uintmax_t)a);
164                         goto invalid;
165                 }
166                 *pa = ofs + offset;
167                 return (I386_PAGE_SIZE - offset);
168         } else {
169                 _kvm_err(kd, kd->program,
170             "_i386_minidump_vatop_pae: virtual address 0x%jx not minidumped",
171                     (uintmax_t)va);
172                 goto invalid;
173         }
174
175 invalid:
176         _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va);
177         return (0);
178 }
179
180 static int
181 _i386_minidump_vatop(kvm_t *kd, kvaddr_t va, off_t *pa)
182 {
183         struct vmstate *vm;
184         i386_physaddr_t offset;
185         i386_pte_t pte;
186         kvaddr_t pteindex;
187         i386_physaddr_t a;
188         off_t ofs;
189         i386_pte_t *ptemap;
190
191         vm = kd->vmst;
192         ptemap = vm->ptemap;
193         offset = va & I386_PAGE_MASK;
194
195         if (va >= vm->hdr.kernbase) {
196                 pteindex = (va - vm->hdr.kernbase) >> I386_PAGE_SHIFT;
197                 if (pteindex >= vm->hdr.ptesize / sizeof(*ptemap))
198                         goto invalid;
199                 pte = le32toh(ptemap[pteindex]);
200                 if ((pte & I386_PG_V) == 0) {
201                         _kvm_err(kd, kd->program,
202                             "_i386_minidump_vatop: pte not valid");
203                         goto invalid;
204                 }
205                 a = pte & I386_PG_FRAME;
206                 ofs = _kvm_pt_find(kd, a);
207                 if (ofs == -1) {
208                         _kvm_err(kd, kd->program,
209             "_i386_minidump_vatop: physical address 0x%jx not in minidump",
210                             (uintmax_t)a);
211                         goto invalid;
212                 }
213                 *pa = ofs + offset;
214                 return (I386_PAGE_SIZE - offset);
215         } else {
216                 _kvm_err(kd, kd->program,
217             "_i386_minidump_vatop: virtual address 0x%jx not minidumped",
218                     (uintmax_t)va);
219                 goto invalid;
220         }
221
222 invalid:
223         _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va);
224         return (0);
225 }
226
227 static int
228 _i386_minidump_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa)
229 {
230
231         if (ISALIVE(kd)) {
232                 _kvm_err(kd, 0, "_i386_minidump_kvatop called in live kernel!");
233                 return (0);
234         }
235         if (kd->vmst->hdr.paemode)
236                 return (_i386_minidump_vatop_pae(kd, va, pa));
237         else
238                 return (_i386_minidump_vatop(kd, va, pa));
239 }
240
241 static struct kvm_arch kvm_i386_minidump = {
242         .ka_probe = _i386_minidump_probe,
243         .ka_initvtop = _i386_minidump_initvtop,
244         .ka_freevtop = _i386_minidump_freevtop,
245         .ka_kvatop = _i386_minidump_kvatop,
246         .ka_native = _i386_native,
247 };
248
249 KVM_ARCH(kvm_i386_minidump);