1 /* Copyright (C) 2004,2005,2006 Andi Kleen, SuSE Labs.
2 Copyright (C) 2008 Intel Corporation
3 Authors: Andi Kleen, Ying Huang
4 Decode IA32/x86-64 machine check events in /dev/mcelog.
5
6 mcelog is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public
8 License as published by the Free Software Foundation; version
9 2.
10
11 mcelog is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should find a copy of v2 of the GNU General Public License somewhere
17 on your Linux system; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19
20 #define _GNU_SOURCE 1
21 #include <sys/fcntl.h>
22 #include <sys/ioctl.h>
23 #ifdef __Linux__
24 #include <asm/types.h>
25 #include <asm/ioctls.h>
26 #include <linux/limits.h>
27 #endif
28 #ifdef __FreeBSD__
29 #include <sys/types.h>
30 #include <sys/queue.h>
31 #include <sys/sysctl.h>
32 #include <machine/cpufunc.h>
33 #include <machine/cputypes.h>
34 #include <machine/specialreg.h>
35 #include <err.h>
36 #include <kvm.h>
37 #include <limits.h>
38 #endif
39 #undef CPU_P4
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <syslog.h>
45 #include <ctype.h>
46 #include <poll.h>
47 #include <time.h>
48 #include <getopt.h>
49 #include <errno.h>
50 #include <stddef.h>
51 #include <assert.h>
52 #include <signal.h>
53 #include <pwd.h>
54 #include <fnmatch.h>
55 #include "mcelog.h"
56 #include "paths.h"
57 #include "k8.h"
58 #include "intel.h"
59 #include "p4.h"
60 #include "dmi.h"
61 #include "dimm.h"
62 #include "tsc.h"
63 #include "version.h"
64 #include "config.h"
65 #include "memutil.h"
66 #include "eventloop.h"
67 #include "memdb.h"
68 #include "server.h"
69 #include "trigger.h"
70 #include "client.h"
71 #include "msg.h"
72 #include "yellow.h"
73 #include "page.h"
74 #include "bus.h"
75 #include "unknown.h"
76
77 struct mca_record {
78 uint64_t mr_status;
79 uint64_t mr_addr;
80 uint64_t mr_misc;
81 uint64_t mr_tsc;
82 int mr_apic_id;
83 int mr_bank;
84 uint64_t mr_mcg_cap;
85 uint64_t mr_mcg_status;
86 int mr_cpu_id;
87 int mr_cpu_vendor_id;
88 int mr_cpu;
89 };
90
91 enum cputype cputype = CPU_GENERIC;
92
93 #ifdef __Linux__
94 char *logfn = LOG_DEV_FILENAME;
95 #endif
96
97 int ignore_nodev;
98 int filter_bogus = 1;
99 int cpu_forced;
100 static double cpumhz;
101 static int cpumhz_forced;
102 int ascii_mode;
103 int dump_raw_ascii;
104 int daemon_mode;
105 static char *inputfile;
106 #ifdef __Linux__
107 char *processor_flags;
108 #endif
109 static int foreground;
110 int filter_memory_errors;
111 static struct config_cred runcred = { .uid = -1U, .gid = -1U };
112 static int numerrors;
113 static char pidfile_default[] = PID_FILE;
114 static char logfile_default[] = LOG_FILE;
115 static char *pidfile = pidfile_default;
116 static char *logfile;
117 #ifdef __FreeBSD__
118 static char *execfile;
119 static char *corefile;
120 #endif
121 static int debug_numerrors;
122 int imc_log = -1;
123 static int check_only = 0;
124 int max_corr_err_counters = 4158;
125
126 static int is_cpu_supported(void);
127
128
disclaimer(void)129 static void disclaimer(void)
130 {
131 Wprintf("Hardware event. This is not a software error.\n");
132 }
133
extended_bankname(unsigned bank)134 static char *extended_bankname(unsigned bank)
135 {
136 static char buf[64];
137 switch (bank) {
138 case MCE_THERMAL_BANK:
139 return "THERMAL EVENT";
140 case MCE_TIMEOUT_BANK:
141 return "Timeout waiting for exception on other CPUs";
142 case K8_MCE_THRESHOLD_BASE ... K8_MCE_THRESHOLD_TOP:
143 return k8_bank_name(bank);
144
145 /* add more extended banks here */
146
147 case MCE_APEI_BANK:
148 return "ACPI/APEI reported error";
149
150 default:
151 sprintf(buf, "Undecoded extended event %x", bank);
152 return buf;
153 }
154 }
155
bankname(unsigned bank)156 static char *bankname(unsigned bank)
157 {
158 static char numeric[64];
159 if (bank >= MCE_EXTENDED_BANK)
160 return extended_bankname(bank);
161
162 switch (cputype) {
163 case CPU_K8:
164 return k8_bank_name(bank);
165 CASE_INTEL_CPUS:
166 return intel_bank_name(bank);
167 /* add banks of other cpu types here */
168 default:
169 sprintf(numeric, "BANK %d", bank);
170 return numeric;
171 }
172 }
173
resolveaddr(unsigned long long addr)174 static void resolveaddr(unsigned long long addr)
175 {
176 if (addr && do_dmi && dmi_forced)
177 dmi_decodeaddr(addr);
178 /* Should check for PCI resources here too */
179 }
180
mce_filter(struct mce * m,unsigned recordlen)181 static int mce_filter(struct mce *m, unsigned recordlen)
182 {
183 if (!filter_bogus)
184 return 1;
185 /* Filter out known broken MCEs */
186 switch (cputype) {
187 case CPU_K8:
188 return mce_filter_k8(m);
189 /* add more buggy CPUs here */
190 CASE_INTEL_CPUS:
191 return mce_filter_intel(m, recordlen);
192 default:
193 case CPU_GENERIC:
194 return 1;
195 }
196 }
197
print_tsc(int cpunum,__u64 tsc,unsigned long time)198 static void print_tsc(int cpunum, __u64 tsc, unsigned long time)
199 {
200 int ret = -1;
201 char *buf = NULL;
202
203 if (cpumhz_forced)
204 ret = decode_tsc_forced(&buf, cpumhz, tsc);
205 else if (!time)
206 ret = decode_tsc_current(&buf, cpunum, cputype, cpumhz, tsc);
207 Wprintf("TSC %llx %s", tsc, ret >= 0 && buf ? buf : "");
208 free(buf);
209 }
210
211 struct cpuid1 {
212 unsigned stepping : 4;
213 unsigned model : 4;
214 unsigned family : 4;
215 unsigned type : 2;
216 unsigned res1 : 2;
217 unsigned ext_model : 4;
218 unsigned ext_family : 8;
219 unsigned res2 : 4;
220 };
221
parse_cpuid(u32 cpuid,u32 * family,u32 * model,u32 * stepping)222 static void parse_cpuid(u32 cpuid, u32 *family, u32 *model, u32 *stepping)
223 {
224 union {
225 struct cpuid1 c;
226 u32 v;
227 } c;
228
229 /* Algorithm from IA32 SDM 2a 3-191 */
230 c.v = cpuid;
231 *family = c.c.family;
232 if (*family == 0xf)
233 *family += c.c.ext_family;
234 *model = c.c.model;
235 if (*family == 6 || *family == 0xf)
236 *model += c.c.ext_model << 4;
237 *stepping = c.c.stepping;
238 }
239
240 #ifdef __Linux__
unparse_cpuid(unsigned family,unsigned model)241 static u32 unparse_cpuid(unsigned family, unsigned model)
242 {
243 union {
244 struct cpuid1 c;
245 u32 v;
246 } c;
247
248 c.c.family = family;
249 if (family >= 0xf) {
250 c.c.family = 0xf;
251 c.c.ext_family = family - 0xf;
252 }
253 c.c.model = model & 0xf;
254 if (family == 6 || family == 0xf)
255 c.c.ext_model = model >> 4;
256 return c.v;
257 }
258 #endif
259
260 static char *cputype_name[] = {
261 [CPU_GENERIC] = "generic CPU",
262 [CPU_P6OLD] = "Intel PPro/P2/P3/old Xeon",
263 [CPU_CORE2] = "Intel Core", /* 65nm and 45nm */
264 [CPU_K8] = "AMD K8 and derivates",
265 [CPU_P4] = "Intel P4",
266 [CPU_NEHALEM] = "Intel Xeon 5500 series / Core i3/5/7 (\"Nehalem/Westmere\")",
267 [CPU_DUNNINGTON] = "Intel Xeon 7400 series",
268 [CPU_TULSA] = "Intel Xeon 7100 series",
269 [CPU_INTEL] = "Intel generic architectural MCA",
270 [CPU_XEON75XX] = "Intel Xeon 7500 series",
271 [CPU_SANDY_BRIDGE] = "Sandy Bridge", /* Fill in better name */
272 [CPU_SANDY_BRIDGE_EP] = "Sandy Bridge EP", /* Fill in better name */
273 [CPU_IVY_BRIDGE] = "Ivy Bridge", /* Fill in better name */
274 [CPU_IVY_BRIDGE_EPEX] = "Intel Xeon v2 (Ivy Bridge) EP/EX", /* Fill in better name */
275 [CPU_HASWELL] = "Haswell", /* Fill in better name */
276 [CPU_HASWELL_EPEX] = "Intel Xeon v3 (Haswell) EP/EX",
277 [CPU_BROADWELL] = "Broadwell",
278 [CPU_BROADWELL_DE] = "Intel Xeon (Broadwell) D family",
279 [CPU_BROADWELL_EPEX] = "Intel Xeon v4 (Broadwell) EP/EX",
280 [CPU_KNIGHTS_LANDING] = "Knights Landing",
281 [CPU_KNIGHTS_MILL] = "Knights Mill",
282 [CPU_ATOM] = "ATOM",
283 [CPU_SKYLAKE] = "Skylake",
284 [CPU_SKYLAKE_XEON] = "Skylake server",
285 [CPU_KABYLAKE] = "Kabylake",
286 [CPU_DENVERTON] = "Denverton",
287 [CPU_ICELAKE] = "Icelake",
288 [CPU_ICELAKE_XEON] = "Icelake server",
289 [CPU_ICELAKE_DE] = "Icelake server D Family",
290 [CPU_TREMONT_D] = "Tremont microserver",
291 [CPU_COMETLAKE] = "Cometlake",
292 [CPU_TIGERLAKE] = "Tigerlake",
293 [CPU_ROCKETLAKE] = "Rocketlake",
294 [CPU_ALDERLAKE] = "Alderlake",
295 [CPU_LAKEFIELD] = "Lakefield",
296 [CPU_SAPPHIRERAPIDS] = "Sapphirerapids server",
297 };
298
299 static struct config_choice cpu_choices[] = {
300 { "generic", CPU_GENERIC },
301 { "p6old", CPU_P6OLD },
302 { "core2", CPU_CORE2 },
303 { "k8", CPU_K8 },
304 { "p4", CPU_P4 },
305 { "dunnington", CPU_DUNNINGTON },
306 { "xeon74xx", CPU_DUNNINGTON },
307 { "xeon7400", CPU_DUNNINGTON },
308 { "xeon5500", CPU_NEHALEM },
309 { "xeon5200", CPU_CORE2 },
310 { "xeon5000", CPU_P4 },
311 { "xeon5100", CPU_CORE2 },
312 { "xeon3100", CPU_CORE2 },
313 { "xeon3200", CPU_CORE2 },
314 { "core_i7", CPU_NEHALEM },
315 { "core_i5", CPU_NEHALEM },
316 { "core_i3", CPU_NEHALEM },
317 { "nehalem", CPU_NEHALEM },
318 { "westmere", CPU_NEHALEM },
319 { "xeon71xx", CPU_TULSA },
320 { "xeon7100", CPU_TULSA },
321 { "tulsa", CPU_TULSA },
322 { "intel", CPU_INTEL },
323 { "xeon75xx", CPU_XEON75XX },
324 { "xeon7500", CPU_XEON75XX },
325 { "xeon7200", CPU_CORE2 },
326 { "xeon7100", CPU_P4 },
327 { "sandybridge", CPU_SANDY_BRIDGE }, /* Fill in better name */
328 { "sandybridge-ep", CPU_SANDY_BRIDGE_EP }, /* Fill in better name */
329 { "ivybridge", CPU_IVY_BRIDGE }, /* Fill in better name */
330 { "ivybridge-ep", CPU_IVY_BRIDGE_EPEX },
331 { "ivybridge-ex", CPU_IVY_BRIDGE_EPEX },
332 { "haswell", CPU_HASWELL }, /* Fill in better name */
333 { "haswell-ep", CPU_HASWELL_EPEX },
334 { "haswell-ex", CPU_HASWELL_EPEX },
335 { "broadwell", CPU_BROADWELL },
336 { "broadwell-d", CPU_BROADWELL_DE },
337 { "broadwell-ep", CPU_BROADWELL_EPEX },
338 { "broadwell-ex", CPU_BROADWELL_EPEX },
339 { "knightslanding", CPU_KNIGHTS_LANDING },
340 { "knightsmill", CPU_KNIGHTS_MILL },
341 { "xeon-v2", CPU_IVY_BRIDGE_EPEX },
342 { "xeon-v3", CPU_HASWELL_EPEX },
343 { "xeon-v4", CPU_BROADWELL_EPEX },
344 { "atom", CPU_ATOM },
345 { "skylake", CPU_SKYLAKE },
346 { "skylake_server", CPU_SKYLAKE_XEON },
347 { "cascadelake_server", CPU_SKYLAKE_XEON },
348 { "kabylake", CPU_KABYLAKE },
349 { "denverton", CPU_DENVERTON },
350 { "icelake_server", CPU_ICELAKE_XEON },
351 { "icelake-d", CPU_ICELAKE_DE },
352 { "snowridge", CPU_TREMONT_D },
353 { "cometlake", CPU_COMETLAKE },
354 { "tigerlake", CPU_TIGERLAKE },
355 { "rocketlake", CPU_ROCKETLAKE },
356 { "alderlake", CPU_ALDERLAKE },
357 { "lakefield", CPU_LAKEFIELD },
358 { "sapphirerapids_server", CPU_SAPPHIRERAPIDS },
359 { NULL }
360 };
361
print_cputypes(void)362 static void print_cputypes(void)
363 {
364 struct config_choice *c;
365 fprintf(stderr, "Valid CPUs:");
366 for (c = cpu_choices; c->name; c++)
367 fprintf(stderr, " %s", c->name);
368 fputc('\n', stderr);
369 }
370
lookup_cputype(char * name)371 static enum cputype lookup_cputype(char *name)
372 {
373 struct config_choice *c;
374 for (c = cpu_choices; c->name; c++) {
375 if (!strcasecmp(name, c->name))
376 return c->val;
377 }
378 fprintf(stderr, "Unknown CPU type `%s' specified\n", name);
379 print_cputypes();
380 exit(1);
381 }
382
383 static char *vendor[] = {
384 [0] = "Intel",
385 [1] = "Cyrix",
386 [2] = "AMD",
387 [3] = "UMC",
388 [4] = "vendor 4",
389 [5] = "Centaur",
390 [6] = "vendor 6",
391 [7] = "Transmeta",
392 [8] = "NSC"
393 };
394
395 #ifdef __Linux__
cpuvendor_to_num(char * name)396 static unsigned cpuvendor_to_num(char *name)
397 {
398 unsigned i;
399 unsigned v;
400 char *end;
401
402 v = strtoul(name, &end, 0);
403 if (end > name)
404 return v;
405 for (i = 0; i < NELE(vendor); i++)
406 if (!strcmp(name, vendor[i]))
407 return i;
408 return 0;
409 }
410 #endif
411
cpuvendor_name(u32 cpuvendor)412 static char *cpuvendor_name(u32 cpuvendor)
413 {
414 return (cpuvendor < NELE(vendor)) ? vendor[cpuvendor] : "Unknown vendor";
415 }
416
setup_cpuid(u32 cpuvendor,u32 cpuid)417 static enum cputype setup_cpuid(u32 cpuvendor, u32 cpuid)
418 {
419 u32 family, model, stepping;
420
421 parse_cpuid(cpuid, &family, &model, &stepping);
422
423 switch (cpuvendor) {
424 case X86_VENDOR_INTEL:
425 return select_intel_cputype(family, model);
426 case X86_VENDOR_AMD:
427 if (family >= 15 && family <= 17)
428 return CPU_K8;
429 /* FALL THROUGH */
430 default:
431 Eprintf("Unknown CPU type vendor %u family %u model %u",
432 cpuvendor, family, model);
433 return CPU_GENERIC;
434 }
435 }
436
mce_cpuid(struct mce * m)437 static void mce_cpuid(struct mce *m)
438 {
439 static int warned;
440 if (m->cpuid) {
441 enum cputype t = setup_cpuid(m->cpuvendor, m->cpuid);
442 if (!cpu_forced)
443 cputype = t;
444 else if (t != cputype && t != CPU_GENERIC && !warned) {
445 Eprintf("Forced cputype %s does not match cpu type %s from mcelog\n",
446 cputype_name[cputype],
447 cputype_name[t]);
448 warned = 1;
449 }
450 } else if (cputype == CPU_GENERIC && !cpu_forced) {
451 is_cpu_supported();
452 }
453 }
454
mce_prepare(struct mce * m)455 static void mce_prepare(struct mce *m)
456 {
457 mce_cpuid(m);
458 if (!m->time)
459 m->time = time(NULL);
460 }
461
dump_mce(struct mce * m,unsigned recordlen)462 static void dump_mce(struct mce *m, unsigned recordlen)
463 {
464 int n;
465 int ismemerr = 0;
466 unsigned cpu = m->extcpu ? m->extcpu : m->cpu;
467
468 /* should not happen */
469 if (!m->finished)
470 Wprintf("not finished?\n");
471 Wprintf("CPU %d %s ", cpu, bankname(m->bank));
472 if (m->tsc)
473 print_tsc(cpu, m->tsc, m->time);
474 Wprintf("\n");
475 if (m->ip)
476 Wprintf("RIP%s %02x:%llx\n",
477 !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
478 m->cs, m->ip);
479 n = 0;
480 if (m->status & MCI_STATUS_MISCV)
481 n += Wprintf("MISC %llx ", m->misc);
482 if (m->status & MCI_STATUS_ADDRV)
483 n += Wprintf("ADDR %llx ", m->addr);
484 if (n > 0)
485 Wprintf("\n");
486 if (m->time) {
487 time_t t = m->time;
488 Wprintf("TIME %llu %s", m->time, ctime(&t));
489 }
490 switch (cputype) {
491 case CPU_K8:
492 decode_k8_mc(m, &ismemerr);
493 break;
494 CASE_INTEL_CPUS:
495 decode_intel_mc(m, cputype, &ismemerr, recordlen);
496 break;
497 /* add handlers for other CPUs here */
498 default:
499 break;
500 }
501 /* decode all status bits here */
502 Wprintf("STATUS %llx MCGSTATUS %llx\n", m->status, m->mcgstatus);
503 n = 0;
504 if (recordlen > offsetof(struct mce, cpuid) && m->mcgcap)
505 n += Wprintf("MCGCAP %llx ", m->mcgcap);
506 if (recordlen > offsetof(struct mce, apicid))
507 n += Wprintf("APICID %x ", m->apicid);
508 if (recordlen > offsetof(struct mce, socketid))
509 n += Wprintf("SOCKETID %x ", m->socketid);
510 if (n > 0)
511 Wprintf("\n");
512
513 if (recordlen > offsetof(struct mce, ppin) && m->ppin)
514 n += Wprintf("PPIN %llx\n", m->ppin);
515
516 if (recordlen > offsetof(struct mce, microcode) && m->microcode)
517 n += Wprintf("MICROCODE %x\n", m->microcode);
518
519 if (recordlen > offsetof(struct mce, cpuid) && m->cpuid) {
520 u32 fam, mod, step;
521 parse_cpuid(m->cpuid, &fam, &mod, &step);
522 Wprintf("CPUID Vendor %s Family %u Model %u Step %u\n",
523 cpuvendor_name(m->cpuvendor),
524 fam,
525 mod,
526 step);
527 }
528 if (cputype != CPU_SANDY_BRIDGE_EP && cputype != CPU_IVY_BRIDGE_EPEX &&
529 cputype != CPU_HASWELL_EPEX && cputype != CPU_BROADWELL &&
530 cputype != CPU_BROADWELL_DE && cputype != CPU_BROADWELL_EPEX &&
531 cputype != CPU_KNIGHTS_LANDING && cputype != CPU_KNIGHTS_MILL &&
532 cputype != CPU_SKYLAKE && cputype != CPU_SKYLAKE_XEON &&
533 cputype != CPU_KABYLAKE && cputype != CPU_DENVERTON &&
534 cputype != CPU_ICELAKE_XEON && cputype != CPU_ICELAKE_DE &&
535 cputype != CPU_TREMONT_D && cputype != CPU_COMETLAKE &&
536 cputype != CPU_TIGERLAKE && cputype != CPU_ROCKETLAKE &&
537 cputype != CPU_ALDERLAKE && cputype != CPU_LAKEFIELD &&
538 cputype != CPU_SAPPHIRERAPIDS)
539 resolveaddr(m->addr);
540 }
541
dump_mce_raw_ascii(struct mce * m,unsigned recordlen)542 static void dump_mce_raw_ascii(struct mce *m, unsigned recordlen)
543 {
544 /* should not happen */
545 if (!m->finished)
546 Wprintf("not finished?\n");
547 Wprintf("CPU %u\n", m->extcpu ? m->extcpu : m->cpu);
548 Wprintf("BANK %d\n", m->bank);
549 Wprintf("TSC %#llx\n", m->tsc);
550 Wprintf("RIP %#02x:%#llx\n", m->cs, m->ip);
551 Wprintf("MISC %#llx\n", m->misc);
552 Wprintf("ADDR %#llx\n", m->addr);
553 Wprintf("STATUS %#llx\n", m->status);
554 Wprintf("MCGSTATUS %#llx\n", m->mcgstatus);
555 if (recordlen > offsetof(struct mce, cpuid))
556 Wprintf("PROCESSOR %u:%#x\n", m->cpuvendor, m->cpuid);
557 #define CPRINT(str, field) \
558 if (recordlen > offsetof(struct mce, field)) \
559 Wprintf(str "\n", m->field)
560 CPRINT("TIME %llu", time);
561 CPRINT("SOCKETID %u", socketid);
562 CPRINT("APICID %u", apicid);
563 CPRINT("MCGCAP %#llx", mcgcap);
564 #undef CPRINT
565 Wprintf("\n");
566 }
567
568 #ifdef __Linux__
is_cpu_supported(void)569 int is_cpu_supported(void)
570 {
571 enum {
572 VENDOR = 1,
573 FAMILY = 2,
574 MODEL = 4,
575 MHZ = 8,
576 FLAGS = 16,
577 ALL = 0x1f
578 } seen = 0;
579 FILE *f;
580 static int checked;
581
582 if (checked)
583 return 1;
584 checked = 1;
585
586 f = fopen("/proc/cpuinfo","r");
587 if (f != NULL) {
588 int family = 0;
589 int model = 0;
590 char vendor[64] = { 0 };
591 char *line = NULL;
592 size_t linelen = 0;
593 double mhz;
594
595 while (getdelim(&line, &linelen, '\n', f) > 0 && seen != ALL) {
596 if (sscanf(line, "vendor_id : %63[^\n]", vendor) == 1)
597 seen |= VENDOR;
598 if (sscanf(line, "cpu family : %d", &family) == 1)
599 seen |= FAMILY;
600 if (sscanf(line, "model : %d", &model) == 1)
601 seen |= MODEL;
602 /* We use only Mhz of the first CPU, assuming they are the same
603 (there are more sanity checks later to make this not as wrong
604 as it sounds) */
605 if (sscanf(line, "cpu MHz : %lf", &mhz) == 1) {
606 if (!cpumhz_forced)
607 cpumhz = mhz;
608 seen |= MHZ;
609 }
610 if (!strncmp(line, "flags", 5) && isspace(line[6])) {
611 processor_flags = line;
612 line = NULL;
613 linelen = 0;
614 seen |= FLAGS;
615 }
616
617 }
618 if (seen == ALL) {
619 if (!strcmp(vendor,"AuthenticAMD")) {
620 if (family == 15) {
621 cputype = CPU_K8;
622 } else if (family >= 16) {
623 Eprintf("ERROR: AMD Processor family %d: mcelog does not support this processor. Please use the edac_mce_amd module instead.\n", family);
624 return 0;
625 }
626 } else if (!strcmp(vendor,"HygonGenuine")) {
627 Eprintf("ERROR: Hygon Processor family %d: mcelog does not support this processor. Please use the edac_mce_amd module instead.\n", family);
628 return 0;
629 } else if (!strcmp(vendor,"GenuineIntel"))
630 cputype = select_intel_cputype(family, model);
631 /* Add checks for other CPUs here */
632 } else {
633 Eprintf("warning: Cannot parse /proc/cpuinfo\n");
634 }
635 fclose(f);
636 free(line);
637 } else
638 Eprintf("warning: Cannot open /proc/cpuinfo\n");
639
640 return 1;
641 }
642 #endif
643
644 #ifdef __FreeBSD__
is_cpu_supported(void)645 int is_cpu_supported(void)
646 {
647 char vendor[20];
648 u_int regs[4];
649 u_int cpu_id;
650 int family, model;
651 static int checked;
652
653 if (checked)
654 return 1;
655
656 checked = 1;
657
658 do_cpuid(0, regs);
659 ((u_int *)vendor)[0] = regs[1];
660 ((u_int *)vendor)[1] = regs[3];
661 ((u_int *)vendor)[2] = regs[2];
662 vendor[12] = 0;
663
664 do_cpuid(1, regs);
665 cpu_id = regs[0];
666 family = CPUID_TO_FAMILY(cpu_id);
667 model = CPUID_TO_MODEL(cpu_id);
668
669 if (cpu_forced)
670 ;
671 else if (!strcmp(vendor,"AuthenticAMD")) {
672 if (family == 15) {
673 cputype = CPU_K8;
674 } else if (family >= 16) {
675 SYSERRprintf("ERROR: AMD Processor family %d: mcelog does not support this processor. Please use the edac_mce_amd module instead.\n", family);
676 return 0;
677 }
678 } else if (!strcmp(vendor,"GenuineIntel"))
679 cputype = select_intel_cputype(family, model);
680 /* Add checks for other CPUs here */
681 else
682 return 1;
683 return 0;
684 }
685 #endif
686
687 #ifdef __Linux__
skipspace(char * s)688 static char *skipspace(char *s)
689 {
690 while (isspace(*s))
691 ++s;
692 return s;
693 }
694 #endif
695
696 #ifdef __Linux__
skip_syslog(char * s)697 static char *skip_syslog(char *s)
698 {
699 char *p;
700
701 /* Handle syslog output */
702 p = strstr(s, "mcelog: ");
703 if (p)
704 return p + sizeof("mcelog: ") - 1;
705 return s;
706 }
707 #endif
708
709 #ifdef __Linux__
skipgunk(char * s)710 static char *skipgunk(char *s)
711 {
712 s = skip_syslog(s);
713
714 s = skipspace(s);
715 if (*s == '<') {
716 s += strcspn(s, ">");
717 if (*s == '>')
718 ++s;
719 }
720 s = skipspace(s);
721 if (*s == '[') {
722 s += strcspn(s, "]");
723 if (*s == ']')
724 ++s;
725 }
726
727 s = skipspace(s);
728
729 if (strncmp(s, "mce: [Hardware Error]:", 22) == 0)
730 s += 22;
731
732 return skipspace(s);
733 }
734 #endif
735
736 #ifdef __Linux__
urange(unsigned val,unsigned lo,unsigned hi)737 static inline int urange(unsigned val, unsigned lo, unsigned hi)
738 {
739 return val >= lo && val <= hi;
740 }
741 #endif
742
743 #ifdef __Linux__
is_short(char * name)744 static int is_short(char *name)
745 {
746 return strlen(name) == 3 &&
747 isupper(name[0]) &&
748 islower(name[1]) &&
749 islower(name[2]);
750 }
751 #endif
752
753 #ifdef __Linux__
skip_date(char * s)754 static unsigned skip_date(char *s)
755 {
756 unsigned day, hour, min, year, sec;
757 char dayname[11];
758 char month[11];
759 unsigned next;
760
761 if (sscanf(s, "%10s %10s %u %u:%u:%u %u%n",
762 dayname, month, &day, &hour, &min, &sec, &year, &next) != 7)
763 return 0;
764 if (!is_short(dayname) || !is_short(month) || !urange(day, 1, 31) ||
765 !urange(hour, 0, 24) || !urange(min, 0, 59) || !urange(sec, 0, 59) ||
766 year < 1900)
767 return 0;
768 return next;
769 }
770 #endif
771
dump_mce_final(struct mce * m,char * symbol,int missing,int recordlen,int dseen)772 static void dump_mce_final(struct mce *m, char *symbol, int missing, int recordlen,
773 int dseen)
774 {
775 m->finished = 1;
776 if (m->cpuid)
777 mce_cpuid(m);
778 if (!dump_raw_ascii) {
779 if (!dseen)
780 disclaimer();
781 dump_mce(m, recordlen);
782 if (symbol[0])
783 Wprintf("RIP: %s\n", symbol);
784 if (missing)
785 Wprintf("(Fields were incomplete)\n");
786 } else
787 dump_mce_raw_ascii(m, recordlen);
788 flushlog();
789 }
790
791 #ifdef __Linux__
792 static char *skip_patterns[] = {
793 "MCA:*",
794 "MCi_MISC register valid*",
795 "MC? status*",
796 "Unsupported new Family*",
797 "Kernel does not support page offline interface",
798 NULL
799 };
800 #endif
801
802 #ifdef __Linux__
match_patterns(char * s,char ** pat)803 static int match_patterns(char *s, char **pat)
804 {
805 for (; *pat; pat++)
806 if (!fnmatch(*pat, s, 0))
807 return 0;
808 return 1;
809 }
810 #endif
811
812 #define FIELD(f) \
813 if (recordlen < endof_field(struct mce, f)) \
814 recordlen = endof_field(struct mce, f)
815
816 /* Decode ASCII input for fatal messages */
817 #ifdef __Linux__
decodefatal(FILE * inf)818 static void decodefatal(FILE *inf)
819 {
820 struct mce m;
821 char *line = NULL;
822 size_t linelen = 0;
823 int missing;
824 char symbol[100];
825 int data;
826 int next;
827 char *s = NULL;
828 unsigned cpuvendor;
829 unsigned recordlen;
830 int disclaimer_seen;
831
832 ascii_mode = 1;
833 if (do_dmi && dmi_forced)
834 Wprintf(
835 "WARNING: with --dmi mcelog --ascii must run on the same machine with the\n"
836 " same BIOS/memory configuration as where the machine check occurred.\n");
837
838 restart:
839 missing = 0;
840 data = 0;
841 next = 0;
842 disclaimer_seen = 0;
843 recordlen = 0;
844 memset(&m, 0, sizeof(struct mce));
845 symbol[0] = '\0';
846 while (next > 0 || getdelim(&line, &linelen, '\n', inf) > 0) {
847 int n = 0;
848 char *start;
849
850 s = next > 0 ? s + next : line;
851 s = skipgunk(s);
852 start = s;
853 next = 0;
854
855 if (!strncmp(s, "CPU ", 4)) {
856 unsigned cpu = 0, bank = 0;
857 n = sscanf(s,
858 "CPU %u: Machine Check%*[ :Ec-x]%16Lx Bank %d: %016Lx%n",
859 &cpu,
860 &m.mcgstatus,
861 &bank,
862 &m.status,
863 &next);
864 if (n == 1) {
865 n = sscanf(s, "CPU %u BANK %u%n", &cpu, &bank,
866 &next);
867 if (n != 2)
868 n = sscanf(s, "CPU %u %u%n", &cpu,
869 &bank, &next);
870 m.cpu = cpu;
871 if (n < 2)
872 missing++;
873 else {
874 m.bank = bank;
875 FIELD(bank);
876 }
877 } else if (n <= 0) {
878 missing++;
879 } else if (n > 1) {
880 FIELD(mcgstatus);
881 m.cpu = cpu;
882 if (n > 2) {
883 m.bank = bank;
884 FIELD(bank);
885 } else if (n > 3)
886 FIELD(status);
887 if (n < 4)
888 missing++;
889 }
890 }
891 else if (!strncmp(s, "STATUS", 6)) {
892 if ((n = sscanf(s,"STATUS %llx%n", &m.status, &next)) < 1)
893 missing++;
894 else
895 FIELD(status);
896 }
897 else if (!strncmp(s, "MCGSTATUS", 6)) {
898 if ((n = sscanf(s,"MCGSTATUS %llx%n", &m.mcgstatus, &next)) < 1)
899 missing++;
900 else
901 FIELD(mcgstatus);
902 }
903 else if (!strncmp(s, "RIP", 3)) {
904 unsigned cs = 0;
905
906 if (!strncmp(s, "RIP !INEXACT!", 13))
907 s += 13;
908 else
909 s += 3;
910
911 n = sscanf(s, "%02x:<%016Lx> {%99s}%n",
912 &cs,
913 &m.ip,
914 symbol, &next);
915 m.cs = cs;
916 if (n < 2)
917 missing++;
918 else
919 FIELD(ip);
920 }
921 else if (!strncmp(s, "TSC",3)) {
922 if ((n = sscanf(s, "TSC %llx%n", &m.tsc, &next)) < 1)
923 missing++;
924 else
925 FIELD(tsc);
926 }
927 else if (!strncmp(s, "ADDR",4)) {
928 if ((n = sscanf(s, "ADDR %llx%n", &m.addr, &next)) < 1)
929 missing++;
930 else
931 FIELD(addr);
932 }
933 else if (!strncmp(s, "MISC",4)) {
934 if ((n = sscanf(s, "MISC %llx%n", &m.misc, &next)) < 1)
935 missing++;
936 else
937 FIELD(misc);
938 }
939 else if (!strncmp(s, "PROCESSOR", 9)) {
940 if ((n = sscanf(s, "PROCESSOR %u:%x%n", &cpuvendor, &m.cpuid, &next)) < 2)
941 missing++;
942 else {
943 m.cpuvendor = cpuvendor;
944 FIELD(cpuid);
945 FIELD(cpuvendor);
946 }
947 }
948 else if (!strncmp(s, "TIME", 4)) {
949 if ((n = sscanf(s, "TIME %llu%n", &m.time, &next)) < 1)
950 missing++;
951 else
952 FIELD(time);
953
954 next += skip_date(s + next);
955 }
956 else if (!strncmp(s, "MCGCAP", 6)) {
957 if ((n = sscanf(s, "MCGCAP %llx%n", &m.mcgcap, &next)) != 1)
958 missing++;
959 else
960 FIELD(mcgcap);
961 }
962 else if (!strncmp(s, "APICID", 6)) {
963 if ((n = sscanf(s, "APICID %x%n", &m.apicid, &next)) != 1)
964 missing++;
965 else
966 FIELD(apicid);
967 }
968 else if (!strncmp(s, "SOCKETID", 8)) {
969 if ((n = sscanf(s, "SOCKETID %u%n", &m.socketid, &next)) != 1)
970 missing++;
971 else
972 FIELD(socketid);
973 }
974 else if (!strncmp(s, "CPUID", 5)) {
975 unsigned fam, mod;
976 char vendor[31];
977
978 if ((n = sscanf(s, "CPUID Vendor %30s Family %u Model %u\n",
979 vendor, &fam, &mod)) < 3)
980 missing++;
981 else {
982 m.cpuvendor = cpuvendor_to_num(vendor);
983 m.cpuid = unparse_cpuid(fam, mod);
984 FIELD(cpuid);
985 FIELD(cpuvendor);
986 }
987 }
988 else if (strstr(s, "HARDWARE ERROR"))
989 disclaimer_seen = 1;
990 else if (!strncmp(s, "(XEN)", 5)) {
991 char *w;
992 unsigned bank, cpu;
993
994 if (strstr(s, "The hardware reports a non fatal, correctable incident occurred")) {
995 w = strstr(s, "CPU");
996 if (w && sscanf(w, "CPU %d", &cpu)) {
997 m.cpu = cpu;
998 FIELD(cpu);
999 }
1000 } else if ((n = sscanf(s, "(XEN) Bank %d: %llx at %llx",
1001 &bank, &m.status, &m.addr) >= 1)) {
1002 m.bank = bank;
1003 FIELD(bank);
1004 if (n >= 2)
1005 FIELD(status);
1006 if (n >= 3)
1007 FIELD(addr);
1008 }
1009 }
1010 else if (!match_patterns(s, skip_patterns))
1011 n = 0;
1012 else {
1013 s = skipspace(s);
1014 if (*s && data)
1015 dump_mce_final(&m, symbol, missing, recordlen, disclaimer_seen);
1016 if (!dump_raw_ascii)
1017 Wprintf("%s", start);
1018 if (*s && data)
1019 goto restart;
1020 }
1021 if (n > 0)
1022 data = 1;
1023 }
1024 free(line);
1025 if (data)
1026 dump_mce_final(&m, symbol, missing, recordlen, disclaimer_seen);
1027 }
1028 #endif
1029
1030 #ifdef __FreeBSD__
1031 /*
1032 * Table used to map cpuid vendor strings and FreeBSD CPU vendor IDs
1033 * to Linux cpuvendor values.
1034 */
1035 static struct {
1036 char *name;
1037 int vendor_id;
1038 u_char cpuvendor;
1039 } vendor_ids[] = {
1040 { "GenuineIntel", CPU_VENDOR_INTEL, 0 },
1041 { "AuthenticAMD", CPU_VENDOR_AMD, 2 },
1042 { "CentaurHauls", CPU_VENDOR_CENTAUR, 5 },
1043 #ifdef __i386__
1044 { "CyrixInstead", CPU_VENDOR_CYRIX, 1 },
1045 { "UMC UMC UMC ", CPU_VENDOR_UMC, 3 },
1046 { "GenuineTMx86", CPU_VENDOR_TRANSMETA, 7 },
1047 { "Geode by NSC", CPU_VENDOR_NSC, 8 },
1048 #endif
1049 };
1050
find_cpu_vendor(const char * vendor)1051 static int find_cpu_vendor(const char *vendor)
1052 {
1053 u_int i;
1054
1055 for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
1056 if (strcmp(vendor, vendor_ids[i].name) == 0)
1057 return (vendor_ids[i].cpuvendor);
1058 return (0xff);
1059 }
1060
find_cpu_vendor_id(const char * vendor)1061 static int find_cpu_vendor_id(const char *vendor)
1062 {
1063 u_int i;
1064
1065 for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
1066 if (strcmp(vendor, vendor_ids[i].name) == 0)
1067 return (vendor_ids[i].vendor_id);
1068 return (0);
1069 }
1070
map_cpu_vendor(int vendor_id)1071 static int map_cpu_vendor(int vendor_id)
1072 {
1073 u_int i;
1074
1075 for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
1076 if (vendor_ids[i].vendor_id == vendor_id)
1077 return (vendor_ids[i].cpuvendor);
1078 return (0xff);
1079 }
1080
1081 /* Convert FreeBSD's struct mca_record into a struct mce. */
convert_mca(struct mca_record * mr,struct mce * mce,int live,size_t len)1082 static void convert_mca(struct mca_record *mr, struct mce *mce, int live,
1083 size_t len)
1084 {
1085 memset(mce, 0, sizeof(*mce));
1086 mce->status = mr->mr_status;
1087 mce->misc = mr->mr_misc;
1088 mce->addr = mr->mr_addr;
1089 mce->mcgstatus = mr->mr_mcg_status;
1090 mce->tsc = mr->mr_tsc;
1091 mce->cpuvendor = map_cpu_vendor(mr->mr_cpu_vendor_id);
1092 mce->cpuid = mr->mr_cpu_id;
1093 mce->bank = mr->mr_bank;
1094 mce->finished = 1;
1095 mce->extcpu = mr->mr_cpu;
1096 mce->apicid = mr->mr_apic_id;
1097 mce->mcgcap = mr->mr_mcg_cap;
1098
1099 /*
1100 * For older live records (from sysctl), fill in some fields
1101 * using registers from the current CPU.
1102 */
1103 if (len < offsetof(struct mca_record, mr_cpu_id) && live) {
1104 char vendor[20];
1105 u_int regs[4];
1106
1107 do_cpuid(0, regs);
1108 ((u_int *)vendor)[0] = regs[1];
1109 ((u_int *)vendor)[1] = regs[3];
1110 ((u_int *)vendor)[2] = regs[2];
1111 vendor[12] = 0;
1112 mce->cpuvendor = find_cpu_vendor(vendor);
1113
1114 do_cpuid(1, regs);
1115 mce->cpuid = regs[0];
1116 }
1117 }
1118
1119 /* Decode ASCII input for fatal messages */
decodefatal(FILE * inf)1120 static void decodefatal(FILE *inf)
1121 {
1122 struct mca_record mr;
1123 struct mce m;
1124 long long val, val2;
1125 char *cp, line[100], *s, symbol[1];
1126 const char *fmt;
1127 int cpu, data, old, missing;
1128 enum rows {
1129 BANK = 0x1,
1130 MCG = 0x2,
1131 VENDOR = 0x4,
1132 CPU = 0x8,
1133 ADDR = 0x10,
1134 MISC = 0x20,
1135 };
1136
1137 symbol[0] = '\0';
1138 data = 0;
1139 missing = 0;
1140 old = 0;
1141 memset(&mr, 0, sizeof(mr));
1142 while ((s = fgets(line, sizeof(line), inf)) != NULL) {
1143 s = strstr(s, "MCA: ");
1144 if (s == NULL)
1145 continue;
1146 s += strlen("MCA: ");
1147
1148 if (strncmp(s, "bank", 4) == 0 || strncmp(s, "Bank", 4) == 0) {
1149 /* Start of a new record, dump the previous one. */
1150 if (data != 0) {
1151 /* Require some minimum data. */
1152 if (data & BANK) {
1153 if (mr.mr_status & MC_STATUS_ADDRV &&
1154 !(data & ADDR))
1155 missing = 1;
1156 if (mr.mr_status & MC_STATUS_MISCV &&
1157 !(data & MISC))
1158 missing = 1;
1159 convert_mca(&mr, &m, 0, sizeof(mr));
1160 mce_cpuid(&m);
1161 dump_mce_final(&m, symbol, missing,
1162 sizeof(struct mce), 0);
1163 }
1164 data = 0;
1165 missing = 0;
1166 memset(&mr, 0, sizeof(mr));
1167 }
1168
1169 if (s[0] == 'b') {
1170 old = 1;
1171 fmt = "bank %d, status 0x%llx";
1172 } else {
1173 old = 0;
1174 fmt = "Bank %d, Status 0x%llx";
1175 }
1176 if (sscanf(s, fmt, &mr.mr_bank, &val) != 2)
1177 missing = 1;
1178 else {
1179 data |= BANK;
1180 mr.mr_status = val;
1181 }
1182 }
1183 if (strncmp(s, "Global", 6) == 0) {
1184 if (sscanf(s, "Global Cap 0x%llx, Status 0x%llx", &val,
1185 &val2) != 2)
1186 missing = 1;
1187 else {
1188 data |= MCG;
1189 mr.mr_mcg_cap = val;
1190 mr.mr_mcg_status = val2;
1191 }
1192 }
1193 if (strncmp(s, "Vendor \"", 8) == 0) {
1194 s += 8;
1195 cp = index(s, '"');
1196 if (cp != NULL) {
1197 *cp = '\0';
1198 mr.mr_cpu_vendor_id = find_cpu_vendor_id(s);
1199 s = cp + 1;
1200 if (sscanf(s, ", ID 0x%x, APIC ID %d",
1201 &mr.mr_cpu_id, &mr.mr_apic_id) != 2)
1202 missing = 1;
1203 else
1204 data |= VENDOR;
1205 } else
1206 missing = 1;
1207 }
1208 if (strncmp(s, "CPU", 3) == 0) {
1209 if (sscanf(s, "CPU %d ", &cpu) != 1)
1210 missing = 1;
1211 else {
1212 data |= CPU;
1213 if (old)
1214 mr.mr_apic_id = cpu;
1215 else
1216 mr.mr_cpu = cpu;
1217 }
1218 }
1219 if (strncmp(s, "Address", 7) == 0) {
1220 if (sscanf(s, "Address 0x%llx", &val) != 1)
1221 missing = 1;
1222 else {
1223 data |= ADDR;
1224 mr.mr_addr = val;
1225 }
1226 }
1227 if (strncmp(s, "Misc", 4) == 0) {
1228 if (sscanf(s, "Misc 0x%llx", &val) != 1)
1229 missing = 1;
1230 else {
1231 data |= MISC;
1232 mr.mr_misc = val;
1233 }
1234 }
1235 }
1236
1237 /* Dump the last record. */
1238 if (data & BANK) {
1239 if (mr.mr_status & MC_STATUS_ADDRV && !(data & ADDR))
1240 missing = 1;
1241 if (mr.mr_status & MC_STATUS_MISCV && !(data & MISC))
1242 missing = 1;
1243 convert_mca(&mr, &m, 0, sizeof(mr));
1244 mce_cpuid(&m);
1245 dump_mce_final(&m, symbol, missing, sizeof(struct mce), 0);
1246 }
1247 }
1248 #endif
1249
remove_pidfile(void)1250 static void remove_pidfile(void)
1251 {
1252 unlink(pidfile);
1253 if (pidfile != pidfile_default)
1254 free(pidfile);
1255 }
1256
signal_exit(int sig)1257 static void signal_exit(int sig)
1258 {
1259 remove_pidfile();
1260 client_cleanup();
1261 _exit(EXIT_SUCCESS);
1262 }
1263
setup_pidfile(char * s)1264 static void setup_pidfile(char *s)
1265 {
1266 char cwd[PATH_MAX];
1267 char *c;
1268
1269 if (*s != '/') {
1270 c = getcwd(cwd, PATH_MAX);
1271 if (!c)
1272 return;
1273 xasprintf(&pidfile, "%s/%s", cwd, s);
1274 } else {
1275 xasprintf(&pidfile, "%s", s);
1276 }
1277
1278 return;
1279 }
1280
write_pidfile(void)1281 static void write_pidfile(void)
1282 {
1283 FILE *f;
1284 atexit(remove_pidfile);
1285 signal(SIGTERM, signal_exit);
1286 signal(SIGINT, signal_exit);
1287 signal(SIGQUIT, signal_exit);
1288 f = fopen(pidfile, "w");
1289 if (!f) {
1290 Eprintf("Cannot open pidfile `%s'", pidfile);
1291 return;
1292 }
1293 fprintf(f, "%u", getpid());
1294 fclose(f);
1295 }
1296
usage(void)1297 void usage(void)
1298 {
1299 fprintf(stderr,
1300 "Usage:\n"
1301 "\n"
1302 " mcelog [options] [mcelogdevice]\n"
1303 "Decode machine check error records from current kernel.\n"
1304 "\n"
1305 " mcelog [options] --daemon\n"
1306 "Run mcelog in daemon mode, waiting for errors from the kernel.\n"
1307 "\n"
1308 " mcelog [options] --client\n"
1309 "Query a currently running mcelog daemon for errors\n"
1310 "\n"
1311 " mcelog [options] --ascii < log\n"
1312 " mcelog [options] --ascii --file log\n"
1313 "Decode machine check ASCII output from kernel logs\n"
1314 #ifdef __FreeBSD_
1315 " mcelog [options] -M vmcore -N kernel\n"
1316 "Decode machine check error records from kernel crashdump.\n"
1317 #endif
1318 "\n"
1319 "Options:\n"
1320 "--version Show the version of mcelog and exit\n"
1321 "--cpu CPU Set CPU type CPU to decode (see below for valid types)\n"
1322 "--intel-cpu FAMILY,MODEL Set CPU type for an Intel CPU based on family and model from cpuid\n"
1323 "--k8 Set the CPU to be an AMD K8\n"
1324 "--p4 Set the CPU to be an Intel Pentium4\n"
1325 "--core2 Set the CPU to be an Intel Core2\n"
1326 "--generic Set the CPU to a generic version\n"
1327 "--cpumhz MHZ Set CPU Mhz to decode time (output unreliable, not needed on new kernels)\n"
1328 "--raw (with --ascii) Dump in raw ASCII format for machine processing\n"
1329 "--daemon Run in background waiting for events (needs newer kernel)\n"
1330 "--client Query a currently running mcelog daemon for errors\n"
1331 "--ignorenodev Exit silently when the device cannot be opened\n"
1332 "--file filename With --ascii read machine check log from filename instead of stdin\n"
1333 "--logfile filename Log decoded machine checks in file filename\n"
1334 "--syslog Log decoded machine checks in syslog (default stdout or syslog for daemon)\n"
1335 "--syslog-error Log decoded machine checks in syslog with error level\n"
1336 "--no-syslog Never log anything to syslog\n"
1337 "--logfile filename Append log output to logfile instead of stdout\n"
1338 "--dmi Use SMBIOS information to decode DIMMs (needs root)\n"
1339 "--no-dmi Don't use SMBIOS information\n"
1340 "--dmi-verbose Dump SMBIOS information (for debugging)\n"
1341 "--filter Inhibit known bogus events (default on)\n"
1342 "--no-filter Don't inhibit known broken events\n"
1343 "--config-file filename Read config information from config file instead of " CONFIG_FILENAME "\n"
1344 "--foreground Keep in foreground (for debugging)\n"
1345 "--num-errors N Only process N errors (for testing)\n"
1346 "--pidfile file Write pid of daemon into file\n"
1347 "--no-imc-log Disable extended iMC logging\n"
1348 "--is-cpu-supported Exit with return code indicating whether the CPU is supported\n"
1349 "--max-corr-err-counters Max page correctable error counters\n"
1350 "--help Display this message.\n"
1351 );
1352 printf("\n");
1353 print_cputypes();
1354 }
1355
1356 enum options {
1357 O_LOGFILE = O_COMMON,
1358 O_K8,
1359 O_P4,
1360 O_GENERIC,
1361 O_CORE2,
1362 O_INTEL_CPU,
1363 O_FILTER,
1364 O_DMI,
1365 O_NO_DMI,
1366 O_DMI_VERBOSE,
1367 O_SYSLOG,
1368 O_NO_SYSLOG,
1369 O_CPUMHZ,
1370 O_SYSLOG_ERROR,
1371 O_RAW,
1372 O_DAEMON,
1373 O_ASCII,
1374 O_CLIENT,
1375 O_VERSION,
1376 O_CONFIG_FILE,
1377 O_CPU,
1378 O_FILE,
1379 O_FOREGROUND,
1380 O_NUMERRORS,
1381 O_PIDFILE,
1382 O_DEBUG_NUMERRORS,
1383 O_NO_IMC_LOG,
1384 O_IS_CPU_SUPPORTED,
1385 O_MAX_CORR_ERR_COUNTERS,
1386 O_HELP,
1387 };
1388
1389 static struct option options[] = {
1390 { "logfile", 1, NULL, O_LOGFILE },
1391 { "k8", 0, NULL, O_K8 },
1392 { "p4", 0, NULL, O_P4 },
1393 { "generic", 0, NULL, O_GENERIC },
1394 { "core2", 0, NULL, O_CORE2 },
1395 { "intel-cpu", 1, NULL, O_INTEL_CPU },
1396 { "ignorenodev", 0, &ignore_nodev, 1 },
1397 { "filter", 0, &filter_bogus, 1 },
1398 { "no-filter", 0, &filter_bogus, 0 },
1399 { "dmi", 0, NULL, O_DMI },
1400 { "no-dmi", 0, NULL, O_NO_DMI },
1401 { "dmi-verbose", 1, NULL, O_DMI_VERBOSE },
1402 { "syslog", 0, NULL, O_SYSLOG },
1403 { "cpumhz", 1, NULL, O_CPUMHZ },
1404 { "syslog-error", 0, NULL, O_SYSLOG_ERROR },
1405 { "dump-raw-ascii", 0, &dump_raw_ascii, 1 },
1406 { "raw", 0, &dump_raw_ascii, 1 },
1407 { "no-syslog", 0, NULL, O_NO_SYSLOG },
1408 { "daemon", 0, NULL, O_DAEMON },
1409 { "ascii", 0, NULL, O_ASCII },
1410 { "file", 1, NULL, O_FILE },
1411 { "version", 0, NULL, O_VERSION },
1412 { "config-file", 1, NULL, O_CONFIG_FILE },
1413 { "cpu", 1, NULL, O_CPU },
1414 { "foreground", 0, NULL, O_FOREGROUND },
1415 { "client", 0, NULL, O_CLIENT },
1416 { "num-errors", 1, NULL, O_NUMERRORS },
1417 { "pidfile", 1, NULL, O_PIDFILE },
1418 { "debug-numerrors", 0, NULL, O_DEBUG_NUMERRORS }, /* undocumented: for testing */
1419 { "no-imc-log", 0, NULL, O_NO_IMC_LOG },
1420 { "max-corr-err-counters", 1, NULL, O_MAX_CORR_ERR_COUNTERS },
1421 { "help", 0, NULL, O_HELP },
1422 { "is-cpu-supported", 0, NULL, O_IS_CPU_SUPPORTED },
1423 {}
1424 };
1425
modifier(int opt)1426 static int modifier(int opt)
1427 {
1428 int v;
1429
1430 switch (opt) {
1431 case O_LOGFILE:
1432 logfile = optarg;
1433 break;
1434 case O_K8:
1435 cputype = CPU_K8;
1436 cpu_forced = 1;
1437 break;
1438 case O_P4:
1439 cputype = CPU_P4;
1440 cpu_forced = 1;
1441 break;
1442 case O_GENERIC:
1443 cputype = CPU_GENERIC;
1444 cpu_forced = 1;
1445 break;
1446 case O_CORE2:
1447 cputype = CPU_CORE2;
1448 cpu_forced = 1;
1449 break;
1450 case O_INTEL_CPU: {
1451 unsigned fam, mod;
1452 if (sscanf(optarg, "%i,%i", &fam, &mod) != 2) {
1453 usage();
1454 exit(1);
1455 }
1456 cputype = select_intel_cputype(fam, mod);
1457 if (cputype == CPU_GENERIC) {
1458 fprintf(stderr, "Unknown Intel CPU\n");
1459 usage();
1460 exit(1);
1461 }
1462 cpu_forced = 1;
1463 break;
1464 }
1465 case O_CPU:
1466 cputype = lookup_cputype(optarg);
1467 cpu_forced = 1;
1468 intel_cpu_init(cputype);
1469 break;
1470 case O_DMI:
1471 do_dmi = 1;
1472 dmi_forced = 1;
1473 break;
1474 case O_NO_DMI:
1475 dmi_forced = 1;
1476 do_dmi = 0;
1477 break;
1478 case O_DMI_VERBOSE:
1479 if (sscanf(optarg, "%i", &v) != 1) {
1480 usage();
1481 exit(1);
1482 }
1483 dmi_set_verbosity(v);
1484 break;
1485 case O_SYSLOG:
1486 openlog("mcelog", 0, LOG_DAEMON);
1487 syslog_opt = SYSLOG_ALL|SYSLOG_FORCE;
1488 break;
1489 case O_NO_SYSLOG:
1490 syslog_opt = SYSLOG_FORCE;
1491 break;
1492 case O_CPUMHZ:
1493 cpumhz_forced = 1;
1494 if (sscanf(optarg, "%lf", &cpumhz) != 1) {
1495 usage();
1496 exit(1);
1497 }
1498 break;
1499 case O_SYSLOG_ERROR:
1500 syslog_level = LOG_ERR;
1501 syslog_opt = SYSLOG_ALL|SYSLOG_FORCE;
1502 break;
1503 case O_DAEMON:
1504 daemon_mode = 1;
1505 if (!(syslog_opt & SYSLOG_FORCE))
1506 syslog_opt = SYSLOG_REMARK|SYSLOG_ERROR;
1507 break;
1508 case O_FILE:
1509 inputfile = optarg;
1510 break;
1511 case O_FOREGROUND:
1512 foreground = 1;
1513 if (!(syslog_opt & SYSLOG_FORCE))
1514 syslog_opt = SYSLOG_FORCE;
1515 break;
1516 case O_NUMERRORS:
1517 numerrors = atoi(optarg);
1518 break;
1519 case O_PIDFILE:
1520 setup_pidfile(optarg);
1521 break;
1522 case O_CONFIG_FILE:
1523 /* parsed in config.c */
1524 break;
1525 case O_DEBUG_NUMERRORS:
1526 debug_numerrors = 1;
1527 break;
1528 case O_NO_IMC_LOG:
1529 imc_log = 0;
1530 break;
1531 case O_MAX_CORR_ERR_COUNTERS:
1532 max_corr_err_counters = atoi(optarg);
1533 break;
1534 case O_IS_CPU_SUPPORTED:
1535 check_only = 1;
1536 break;
1537 case O_HELP:
1538 usage();
1539 exit(0);
1540 break;
1541 #ifdef __FreeBSD__
1542 case 'M':
1543 corefile = strdup(optarg);
1544 break;
1545 case 'N':
1546 execfile = strdup(optarg);
1547 break;
1548 #endif
1549 case 0:
1550 break;
1551 default:
1552 return 0;
1553 }
1554 return 1;
1555 }
1556
modifier_finish(void)1557 static void modifier_finish(void)
1558 {
1559 if(!foreground && daemon_mode && !logfile && !(syslog_opt & SYSLOG_LOG)) {
1560 logfile = logfile_default;
1561 }
1562 if (logfile) {
1563 if (open_logfile(logfile) < 0) {
1564 if (daemon_mode && !(syslog_opt & SYSLOG_FORCE))
1565 syslog_opt = SYSLOG_ALL;
1566 SYSERRprintf("Cannot open logfile %s", logfile);
1567 if (!daemon_mode)
1568 exit(1);
1569 }
1570 }
1571 }
1572
argsleft(int ac,char ** av)1573 void argsleft(int ac, char **av)
1574 {
1575 int opt;
1576
1577 while ((opt = getopt_long(ac, av, "", options, NULL)) != -1) {
1578 if (modifier(opt) != 1) {
1579 usage();
1580 exit(1);
1581 }
1582 }
1583 }
1584
no_syslog(void)1585 void no_syslog(void)
1586 {
1587 if (!(syslog_opt & SYSLOG_FORCE))
1588 syslog_opt = 0;
1589 }
1590
combined_modifier(int opt)1591 static int combined_modifier(int opt)
1592 {
1593 int r = modifier(opt);
1594 return r;
1595 }
1596
general_setup(void)1597 static void general_setup(void)
1598 {
1599 #ifdef __Linux__
1600 trigger_setup();
1601 yellow_setup();
1602 bus_setup();
1603 unknown_setup();
1604 #endif
1605 config_cred("global", "run-credentials", &runcred);
1606 if (config_bool("global", "filter-memory-errors") == 1)
1607 filter_memory_errors = 1;
1608 }
1609
drop_cred(void)1610 static void drop_cred(void)
1611 {
1612 if (runcred.uid != -1U && runcred.gid == -1U) {
1613 struct passwd *pw = getpwuid(runcred.uid);
1614 if (pw)
1615 runcred.gid = pw->pw_gid;
1616 }
1617 if (runcred.gid != -1U) {
1618 if (setgid(runcred.gid) < 0)
1619 SYSERRprintf("Cannot change group to %d", runcred.gid);
1620 }
1621 if (runcred.uid != -1U) {
1622 if (setuid(runcred.uid) < 0)
1623 SYSERRprintf("Cannot change user to %d", runcred.uid);
1624 }
1625 }
1626
1627 #ifdef __Linux__
process(int fd,unsigned recordlen,unsigned loglen,char * buf)1628 static void process(int fd, unsigned recordlen, unsigned loglen, char *buf)
1629 {
1630 int i;
1631 int len, count;
1632 int finish = 0, flags;
1633
1634 if (recordlen == 0) {
1635 Wprintf("no data in mce record\n");
1636 return;
1637 }
1638
1639 len = read(fd, buf, recordlen * loglen);
1640 if (len < 0) {
1641 SYSERRprintf("mcelog read");
1642 return;
1643 }
1644
1645 count = len / (int)recordlen;
1646 if (count == (int)loglen) {
1647 if ((ioctl(fd, MCE_GETCLEAR_FLAGS, &flags) == 0) &&
1648 (flags & (1 << MCE_OVERFLOW)))
1649 Eprintf("Warning: MCE buffer is overflowed.\n");
1650 }
1651
1652 for (i = 0; (i < count) && !finish; i++) {
1653 struct mce *mce = (struct mce *)(buf + i*recordlen);
1654 mce_prepare(mce);
1655 if (numerrors > 0 && --numerrors == 0)
1656 finish = 1;
1657 if (!mce_filter(mce, recordlen))
1658 continue;
1659 if (!dump_raw_ascii) {
1660 disclaimer();
1661 Wprintf("MCE %d\n", i);
1662 dump_mce(mce, recordlen);
1663 } else
1664 dump_mce_raw_ascii(mce, recordlen);
1665 flushlog();
1666 }
1667
1668 if (debug_numerrors && numerrors <= 0)
1669 finish = 1;
1670
1671 if (recordlen > sizeof(struct mce)) {
1672 Eprintf("warning: %lu bytes ignored in each record\n",
1673 (unsigned long)recordlen - sizeof(struct mce));
1674 Eprintf("consider an update\n");
1675 }
1676
1677 if (finish)
1678 exit(0);
1679 }
1680 #endif
1681
1682 #ifdef __FreeBSD__
1683 #ifdef LOCAL_HACK
1684 struct mca_record_old {
1685 uint64_t mr_status;
1686 uint64_t mr_addr;
1687 uint64_t mr_misc;
1688 uint64_t mr_tsc;
1689 int mr_apic_id;
1690 int mr_bank;
1691 };
1692 #endif
1693
1694 struct mca_record_internal {
1695 struct mca_record rec;
1696 int logged;
1697 STAILQ_ENTRY(mca_internal) link;
1698 };
1699
1700 #ifdef LOCAL_HACK
1701 struct mca_record_internal_old {
1702 struct mca_record_old rec;
1703 int logged;
1704 STAILQ_ENTRY(mca_internal) link;
1705 };
1706 #endif
1707
1708 static struct nlist nl[] = {
1709 #define X_MCA_RECORDS 0
1710 { .n_name = "_mca_records" },
1711 #ifdef LOCAL_HACK
1712 #define X_SNAPDATE 1
1713 { .n_name = "_snapdate" },
1714 #endif
1715 { .n_name = NULL },
1716 };
1717
1718 static int
kread(kvm_t * kvm,void * kvm_pointer,void * buf,size_t size,size_t offset)1719 kread(kvm_t *kvm, void *kvm_pointer, void *buf, size_t size, size_t offset)
1720 {
1721 ssize_t ret;
1722
1723 ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, buf, size);
1724 if (ret < 0 || (size_t)ret != size)
1725 return (-1);
1726 return (0);
1727 }
1728
1729 static int
kread_symbol(kvm_t * kvm,int index,void * buf,size_t size)1730 kread_symbol(kvm_t *kvm, int index, void *buf, size_t size)
1731 {
1732 ssize_t ret;
1733
1734 ret = kvm_read(kvm, nl[index].n_value, buf, size);
1735 if (ret < 0 || (size_t)ret != size)
1736 return (-1);
1737 return (0);
1738 }
1739
process_kvm(const char * execfile,const char * corefile)1740 static void process_kvm(const char *execfile, const char *corefile)
1741 {
1742 struct mca_record mr, *mrp;
1743 struct mce mce;
1744 char errbuf[_POSIX2_LINE_MAX];
1745 kvm_t *kvm;
1746 size_t record_size, link_offset;
1747 int i;
1748 #ifdef LOCAL_HACK
1749 int snapdate;
1750 #endif
1751
1752 kvm = kvm_openfiles(execfile, corefile, NULL, O_RDONLY, errbuf);
1753 if (kvm == NULL)
1754 errx(1, "kvm_openfiles: %s", errbuf);
1755 if (kvm_nlist(kvm, nl) != 0)
1756 errx(1, "kvm_nlist: %s", kvm_geterr(kvm));
1757
1758 #ifdef LOCAL_HACK
1759 if (kread_symbol(kvm, X_SNAPDATE, &snapdate, sizeof(snapdate)) < 0)
1760 errx(1, "kvm_read(snapdate) failed");
1761 #endif
1762 /* stqh_first is the first pointer at this address. */
1763 if (kread_symbol(kvm, X_MCA_RECORDS, &mrp, sizeof(mrp)) < 0)
1764 errx(1, "kvm_read(mca_records) failed");
1765 #ifdef LOCAL_HACK
1766 if (snapdate >= 20100329) {
1767 #endif
1768 record_size = sizeof(struct mca_record);
1769 link_offset = __offsetof(struct mca_record_internal,
1770 link.stqe_next);
1771 #ifdef LOCAL_HACK
1772 } else {
1773 record_size = sizeof(struct mca_record_old);
1774 link_offset = __offsetof(struct mca_record_internal_old,
1775 link.stqe_next);
1776 }
1777 #endif
1778
1779 for (i = 0; mrp != NULL; i++) {
1780 memset(&mr, 0, sizeof(mr));
1781 if (kread(kvm, mrp, &mr, record_size, 0) < 0)
1782 break;
1783 if (kread(kvm, mrp, &mrp, sizeof(mrp), link_offset) < 0)
1784 mrp = NULL;
1785
1786 convert_mca(&mr, &mce, 1, record_size);
1787 mce_prepare(&mce);
1788 if (!mce_filter(&mce, sizeof(struct mce)))
1789 continue;
1790 if (!dump_raw_ascii) {
1791 disclaimer();
1792 Wprintf("MCE %d\n", i);
1793 dump_mce(&mce, sizeof(struct mce));
1794 } else
1795 dump_mce_raw_ascii(&mce, sizeof(struct mce));
1796 flushlog();
1797 }
1798
1799 exit(0);
1800 }
1801
process_live(void)1802 static void process_live(void)
1803 {
1804 struct mca_record mr;
1805 struct mce mce;
1806 int mib[4];
1807 size_t len;
1808 int count, finish, i;
1809
1810 len = sizeof(count);
1811 if (sysctlbyname("hw.mca.count", &count, &len, NULL, 0) < 0)
1812 return;
1813
1814 len = 4;
1815 if (sysctlnametomib("hw.mca.records", mib, &len) < 0)
1816 return;
1817
1818 finish = 0;
1819 for (i = 0; i < count; i++) {
1820 mib[3] = i;
1821 len = sizeof(mr);
1822 memset(&mr, 0, sizeof(mr));
1823 if (sysctl(mib, 4, &mr, &len, NULL, 0) < 0) {
1824 warn("sysctl(hw.mca.records.%d)", i);
1825 continue;
1826 }
1827
1828 convert_mca(&mr, &mce, 1, len);
1829 mce_prepare(&mce);
1830 if (numerrors > 0 && --numerrors == 0)
1831 finish = 1;
1832 if (!mce_filter(&mce, sizeof(struct mce)))
1833 continue;
1834 if (!dump_raw_ascii) {
1835 disclaimer();
1836 Wprintf("MCE %d\n", i);
1837 dump_mce(&mce, sizeof(struct mce));
1838 } else
1839 dump_mce_raw_ascii(&mce, sizeof(struct mce));
1840 flushlog();
1841 }
1842
1843 if (finish)
1844 exit(0);
1845 }
1846 #endif
1847
noargs(int ac,char ** av)1848 static void noargs(int ac, char **av)
1849 {
1850 if (getopt_long(ac, av, "", options, NULL) != -1) {
1851 usage();
1852 exit(1);
1853 }
1854 }
1855
parse_config(char ** av)1856 static void parse_config(char **av)
1857 {
1858 static const char config_fn[] = CONFIG_FILENAME;
1859 const char *fn = config_file(av, config_fn);
1860 if (!fn) {
1861 usage();
1862 exit(1);
1863 }
1864 if (parse_config_file(fn) < 0) {
1865 /* If it's the default file don't complain if it isn't there */
1866 if (fn != config_fn) {
1867 fprintf(stderr, "Cannot open config file %s\n", fn);
1868 exit(1);
1869 }
1870 return;
1871 }
1872 config_options(options, combined_modifier);
1873 }
1874
ascii_command(int ac,char ** av)1875 static void ascii_command(int ac, char **av)
1876 {
1877 FILE *f = stdin;
1878
1879 argsleft(ac, av);
1880 if (inputfile) {
1881 f = fopen(inputfile, "r");
1882 if (!f) {
1883 fprintf(stderr, "Cannot open input file `%s': %s\n",
1884 inputfile, strerror(errno));
1885 exit(1);
1886 }
1887 /* f closed by exit */
1888 }
1889 no_syslog();
1890 checkdmi();
1891 decodefatal(f);
1892 }
1893
client_command(int ac,char ** av)1894 static void client_command(int ac, char **av)
1895 {
1896 argsleft(ac, av);
1897 no_syslog();
1898 // XXX modifiers
1899 ask_server("dump all bios\n");
1900 ask_server("pages\n");
1901 }
1902
1903 struct mcefd_data {
1904 unsigned loglen;
1905 unsigned recordlen;
1906 char *buf;
1907 };
1908
1909 #ifdef __Linux__
process_mcefd(struct pollfd * pfd,void * data)1910 static void process_mcefd(struct pollfd *pfd, void *data)
1911 {
1912 struct mcefd_data *d = (struct mcefd_data *)data;
1913 assert((pfd->revents & POLLIN) != 0);
1914 process(pfd->fd, d->recordlen, d->loglen, d->buf);
1915 }
1916 #endif
1917
handle_sigusr1(int sig)1918 static void handle_sigusr1(int sig)
1919 {
1920 reopenlog();
1921 }
1922
main(int ac,char ** av)1923 int main(int ac, char **av)
1924 {
1925 #ifdef __Linux__
1926 struct mcefd_data d = {};
1927 int fd;
1928 #endif
1929 int opt;
1930 parse_config(av);
1931
1932 #ifdef __FreeBSD
1933 while ((opt = getopt_long(ac, av, "M:N:", options, NULL)) != -1) {
1934 #else
1935 while ((opt = getopt_long(ac, av, "", options, NULL)) != -1) {
1936 #endif
1937 if (opt == '?') {
1938 usage();
1939 exit(1);
1940 } else if (combined_modifier(opt) > 0) {
1941 continue;
1942 } else if (opt == O_ASCII) {
1943 ascii_command(ac, av);
1944 exit(0);
1945 } else if (opt == O_CLIENT) {
1946 client_command(ac, av);
1947 exit(0);
1948 } else if (opt == O_VERSION) {
1949 noargs(ac, av);
1950 fprintf(stderr, "mcelog %s\n", MCELOG_VERSION);
1951 exit(0);
1952 } else if (opt == 0)
1953 break;
1954 }
1955
1956 /* before doing anything else let's see if the CPUs are supported */
1957 #ifdef __Linux__
1958 if (!cpu_forced && !is_cpu_supported()) {
1959 if (!check_only)
1960 fprintf(stderr, "CPU is unsupported\n");
1961 exit(1);
1962 }
1963 #endif
1964 if (check_only)
1965 exit(0);
1966
1967 /* If the user didn't tell us not to use iMC logging, check if CPU supports it */
1968 if (imc_log == -1) {
1969 switch (cputype) {
1970 case CPU_SANDY_BRIDGE_EP:
1971 case CPU_IVY_BRIDGE_EPEX:
1972 case CPU_HASWELL_EPEX:
1973 imc_log = 1;
1974 break;
1975 default:
1976 imc_log = 0;
1977 break;
1978 }
1979 }
1980
1981 modifier_finish();
1982 #ifdef __Linux__
1983 if (av[optind])
1984 logfn = av[optind++];
1985 #endif
1986 if (av[optind]) {
1987 usage();
1988 #ifdef __FreeBSD__
1989 if ((corefile != NULL) ^ (execfile != NULL) ||
1990 (corefile != NULL && daemon_mode))
1991 usage();
1992 #endif
1993 exit(1);
1994 }
1995 checkdmi();
1996 general_setup();
1997
1998 #ifdef __Linux__
1999 fd = open(logfn, O_RDONLY);
2000 if (fd < 0) {
2001 if (ignore_nodev)
2002 exit(0);
2003 SYSERRprintf("Cannot open `%s'", logfn);
2004 exit(1);
2005 }
2006
2007 if (ioctl(fd, MCE_GET_RECORD_LEN, &d.recordlen) < 0)
2008 err("MCE_GET_RECORD_LEN");
2009 if (ioctl(fd, MCE_GET_LOG_LEN, &d.loglen) < 0)
2010 err("MCE_GET_LOG_LEN");
2011
2012 d.buf = xalloc(d.recordlen * d.loglen);
2013 #endif
2014 if (daemon_mode) {
2015 prefill_memdb(do_dmi);
2016 if (!do_dmi)
2017 closedmi();
2018 server_setup();
2019 #ifdef __Linux__
2020 page_setup();
2021 #endif
2022 if (imc_log)
2023 set_imc_log(cputype);
2024 drop_cred();
2025 #ifdef __Linux__
2026 register_pollcb(fd, POLLIN, process_mcefd, &d);
2027 #endif
2028 if (!foreground && daemon(0, need_stdout()) < 0)
2029 err("daemon");
2030 if (pidfile)
2031 write_pidfile();
2032 signal(SIGUSR1, handle_sigusr1);
2033 #ifdef __Linux__
2034 event_signal(SIGUSR1);
2035 #endif
2036 eventloop();
2037 } else {
2038 #ifdef __Linux__
2039 process(fd, d.recordlen, d.loglen, d.buf);
2040 #endif
2041 #ifdef __FreeBSD__
2042 if (corefile != NULL)
2043 process_kvm(execfile, corefile);
2044 else
2045 process_live();
2046 #endif
2047 }
2048 #ifdef __Linux__
2049 trigger_wait();
2050 #endif
2051
2052 exit(0);
2053 }
2054