aboutsummaryrefslogtreecommitdiff
path: root/sysutils/mcelog
diff options
context:
space:
mode:
authorRyan Steinmetz <zi@FreeBSD.org>2011-10-15 02:53:31 +0000
committerRyan Steinmetz <zi@FreeBSD.org>2011-10-15 02:53:31 +0000
commit6e9151ca055629e8cb7a9bb13be28967ebcf2c61 (patch)
tree63c7b2a3e84449a8af4085b00a4c91e88ef541ac /sysutils/mcelog
parent2e567b748dfc85a433ba5880fe1d9394453600c8 (diff)
downloadports-6e9151ca055629e8cb7a9bb13be28967ebcf2c61.tar.gz
ports-6e9151ca055629e8cb7a9bb13be28967ebcf2c61.zip
Notes
Diffstat (limited to 'sysutils/mcelog')
-rw-r--r--sysutils/mcelog/Makefile38
-rw-r--r--sysutils/mcelog/distinfo2
-rw-r--r--sysutils/mcelog/files/memstream.c133
-rw-r--r--sysutils/mcelog/files/patch-Makefile48
-rw-r--r--sysutils/mcelog/files/patch-cache.c26
-rw-r--r--sysutils/mcelog/files/patch-client.c20
-rw-r--r--sysutils/mcelog/files/patch-config.c34
-rw-r--r--sysutils/mcelog/files/patch-eventloop.c38
-rw-r--r--sysutils/mcelog/files/patch-intel.c21
-rw-r--r--sysutils/mcelog/files/patch-mcelog.c680
-rw-r--r--sysutils/mcelog/files/patch-mcelog.h25
-rw-r--r--sysutils/mcelog/files/patch-memdb.c12
-rw-r--r--sysutils/mcelog/files/patch-p4.c13
-rw-r--r--sysutils/mcelog/files/patch-server.c79
-rw-r--r--sysutils/mcelog/files/patch-tsc.c95
-rw-r--r--sysutils/mcelog/pkg-descr15
-rw-r--r--sysutils/mcelog/pkg-message7
17 files changed, 1286 insertions, 0 deletions
diff --git a/sysutils/mcelog/Makefile b/sysutils/mcelog/Makefile
new file mode 100644
index 000000000000..84058cf05e78
--- /dev/null
+++ b/sysutils/mcelog/Makefile
@@ -0,0 +1,38 @@
+# New ports collection makefile for: mcelog
+# Date created: 1 October 2011
+# Whom: Jeremy Chadwick <freebsd@jdc.parodius.com>
+#
+# $FreeBSD$
+#
+
+PORTNAME= mcelog
+DISTVERSION= 1.0pre2
+CATEGORIES= sysutils
+MASTER_SITES= ftp://ftp.kernel.org/pub/linux/utils/cpu/mce/ \
+ http://147.52.159.12/mirrors/ftp.kernel.org/pub/linux/utils/cpu/mce/
+
+MAINTAINER= freebsd@jdc.parodius.com
+COMMENT= Collects and decodes Machine Check Exception data
+
+LICENSE= GPLv2
+
+PATCH_STRIP= -p1
+
+USE_GMAKE= yes
+MAKE_ENV+= FREEBSD=1
+LDFLAGS= -lkvm
+
+PLIST_FILES= bin/mcelog
+MAN8= mcelog.8
+
+post-patch:
+ @${CP} ${FILESDIR}/memstream.c ${WRKSRC}/memstream.c
+
+do-install:
+ ${INSTALL_PROGRAM} ${WRKSRC}/mcelog ${PREFIX}/bin
+ ${INSTALL_MAN} ${WRKSRC}/mcelog.8 ${MAN8PREFIX}/man/man8
+
+post-install:
+ @${CAT} ${PKGMESSAGE}
+
+.include <bsd.port.mk>
diff --git a/sysutils/mcelog/distinfo b/sysutils/mcelog/distinfo
new file mode 100644
index 000000000000..9da29a94e70b
--- /dev/null
+++ b/sysutils/mcelog/distinfo
@@ -0,0 +1,2 @@
+SHA256 (mcelog-1.0pre2.tar.gz) = 39bec2a19e2548afe9dbc80f6f9dcee6664fffa7ccc142aeb5e1f8c217c1705c
+SIZE (mcelog-1.0pre2.tar.gz) = 174553
diff --git a/sysutils/mcelog/files/memstream.c b/sysutils/mcelog/files/memstream.c
new file mode 100644
index 000000000000..20cbf29b472c
--- /dev/null
+++ b/sysutils/mcelog/files/memstream.c
@@ -0,0 +1,133 @@
+/* Use funopen(3) to provide open_memstream(3) like functionality. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+struct memstream {
+ char **cp;
+ size_t *lenp;
+ size_t offset;
+};
+
+FILE *
+open_memstream(char **cp, size_t *lenp);
+
+static void
+memstream_grow(struct memstream *ms, size_t newsize)
+{
+ char *buf;
+
+ if (newsize > *ms->lenp) {
+ buf = realloc(*ms->cp, newsize + 1);
+ if (buf != NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "MS: %p growing from %zd to %zd\n",
+ ms, *ms->lenp, newsize);
+#endif
+ memset(buf + *ms->lenp + 1, 0, newsize - *ms->lenp);
+ *ms->cp = buf;
+ *ms->lenp = newsize;
+ }
+ }
+}
+
+static int
+memstream_read(void *cookie, char *buf, int len)
+{
+ struct memstream *ms;
+ int tocopy;
+
+ ms = cookie;
+ memstream_grow(ms, ms->offset + len);
+ tocopy = *ms->lenp - ms->offset;
+ if (len < tocopy)
+ tocopy = len;
+ memcpy(buf, *ms->cp + ms->offset, tocopy);
+ ms->offset += tocopy;
+#ifdef DEBUG
+ fprintf(stderr, "MS: read(%p, %d) = %d\n", ms, len, tocopy);
+#endif
+ return (tocopy);
+}
+
+static int
+memstream_write(void *cookie, const char *buf, int len)
+{
+ struct memstream *ms;
+ int tocopy;
+
+ ms = cookie;
+ memstream_grow(ms, ms->offset + len);
+ tocopy = *ms->lenp - ms->offset;
+ if (len < tocopy)
+ tocopy = len;
+ memcpy(*ms->cp + ms->offset, buf, tocopy);
+ ms->offset += tocopy;
+#ifdef DEBUG
+ fprintf(stderr, "MS: write(%p, %d) = %d\n", ms, len, tocopy);
+#endif
+ return (tocopy);
+}
+
+static fpos_t
+memstream_seek(void *cookie, fpos_t pos, int whence)
+{
+ struct memstream *ms;
+#ifdef DEBUG
+ size_t old;
+#endif
+
+ ms = cookie;
+#ifdef DEBUG
+ old = ms->offset;
+#endif
+ switch (whence) {
+ case SEEK_SET:
+ ms->offset = pos;
+ break;
+ case SEEK_CUR:
+ ms->offset += pos;
+ break;
+ case SEEK_END:
+ ms->offset = *ms->lenp + pos;
+ break;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "MS: seek(%p, %zd, %d) %zd -> %zd\n", ms, pos, whence,
+ old, ms->offset);
+#endif
+ return (ms->offset);
+}
+
+static int
+memstream_close(void *cookie)
+{
+
+ free(cookie);
+ return (0);
+}
+
+FILE *
+open_memstream(char **cp, size_t *lenp)
+{
+ struct memstream *ms;
+ int save_errno;
+ FILE *fp;
+
+ *cp = NULL;
+ *lenp = 0;
+ ms = malloc(sizeof(*ms));
+ ms->cp = cp;
+ ms->lenp = lenp;
+ ms->offset = 0;
+ fp = funopen(ms, memstream_read, memstream_write, memstream_seek,
+ memstream_close);
+ if (fp == NULL) {
+ save_errno = errno;
+ free(ms);
+ errno = save_errno;
+ }
+ return (fp);
+}
diff --git a/sysutils/mcelog/files/patch-Makefile b/sysutils/mcelog/files/patch-Makefile
new file mode 100644
index 000000000000..96fa1ad39bdd
--- /dev/null
+++ b/sysutils/mcelog/files/patch-Makefile
@@ -0,0 +1,48 @@
+--- ./Makefile.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./Makefile 2011-10-14 22:36:47.000000000 -0400
+@@ -1,5 +1,5 @@
+ CFLAGS := -g -Os
+-prefix := /usr
++prefix := /usr/local
+ etcprefix :=
+ # Define appropiately for your distribution
+ # DOCDIR := /usr/share/doc/packages/mcelog
+@@ -28,10 +28,18 @@
+
+ .PHONY: install clean depend
+
++LIBS :=
+ OBJ := p4.o k8.o mcelog.o dmi.o tsc.o core2.o bitfield.o intel.o \
+ nehalem.o dunnington.o tulsa.o config.o memutil.o msg.o \
+- eventloop.o leaky-bucket.o memdb.o server.o trigger.o \
+- client.o cache.o sysfs.o yellow.o page.o rbtree.o
++ eventloop.o leaky-bucket.o memdb.o server.o client.o \
++ cache.o rbtree.o
++ifndef FREEBSD
++OBJ += page.o trigger.o sysfs.o yellow.o
++endif
++ifdef FREEBSD
++OBJ += memstream.o
++LIBS += -lkvm
++endif
+ DISKDB_OBJ := diskdb.o dimm.o db.o
+ CLEAN := mcelog dmi tsc dbquery .depend .depend.X dbquery.o ${DISKDB_OBJ}
+ DOC := mce.pdf
+@@ -47,7 +55,7 @@
+
+ SRC := $(OBJ:.o=.c)
+
+-mcelog: ${OBJ}
++mcelog: ${OBJ} ${LIBS}
+
+ # dbquery intentionally not installed by default
+ install: mcelog
+@@ -81,8 +89,6 @@
+ .depend: ${SRC}
+ ${CC} -MM -I. ${SRC} > .depend.X && mv .depend.X .depend
+
+-include .depend
+-
+ Makefile: .depend
+
+ .PHONY: iccverify src test
diff --git a/sysutils/mcelog/files/patch-cache.c b/sysutils/mcelog/files/patch-cache.c
new file mode 100644
index 000000000000..f9ebf538b5ff
--- /dev/null
+++ b/sysutils/mcelog/files/patch-cache.c
@@ -0,0 +1,26 @@
+--- ./cache.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./cache.c 2011-10-14 22:36:47.000000000 -0400
+@@ -27,6 +27,7 @@
+ #include "sysfs.h"
+ #include "cache.h"
+
++#ifdef __Linux__
+ struct cache {
+ unsigned level;
+ /* Numerical values must match MCACOD */
+@@ -164,6 +165,15 @@
+ Wprintf("Cannot find sysfs cache for CPU %d", cpu);
+ return -1;
+ }
++#endif
++
++#ifdef __FreeBSD__
++int cache_to_cpus(int cpu, unsigned level, unsigned type,
++ int *cpulen, unsigned **cpumap)
++{
++ return -1;
++}
++#endif
+
+ #ifdef TEST
+ main()
diff --git a/sysutils/mcelog/files/patch-client.c b/sysutils/mcelog/files/patch-client.c
new file mode 100644
index 000000000000..222b7ad4fbe4
--- /dev/null
+++ b/sysutils/mcelog/files/patch-client.c
@@ -0,0 +1,20 @@
+--- ./client.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./client.c 2011-10-14 22:36:47.000000000 -0400
+@@ -18,6 +18,7 @@
+ #include <stdio.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
++#include <string.h>
+ #include <unistd.h>
+ #include "mcelog.h"
+ #include "client.h"
+@@ -48,6 +49,9 @@
+ sizeof(struct sockaddr_un)) < 0)
+ SYSERRprintf("client connect");
+
++#ifdef __FreeBSD__
++ /* XXX: Need to use sendmsg() to send a SCM_CREDS control message. */
++#endif
+ n = strlen(command);
+ if (write(fd, command, n) != n)
+ SYSERRprintf("client command write");
diff --git a/sysutils/mcelog/files/patch-config.c b/sysutils/mcelog/files/patch-config.c
new file mode 100644
index 000000000000..d8f716f9b1bb
--- /dev/null
+++ b/sysutils/mcelog/files/patch-config.c
@@ -0,0 +1,34 @@
+--- ./config.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./config.c 2011-10-14 22:36:47.000000000 -0400
+@@ -18,6 +18,9 @@
+ Author: Andi Kleen
+ */
+ #define _GNU_SOURCE 1
++#ifdef __FreeBSD__
++#include <sys/param.h>
++#endif
+ #include <stdio.h>
+ #include <string.h>
+ #include <ctype.h>
+@@ -126,6 +129,21 @@
+ return s;
+ }
+
++#if defined(__FreeBSD__) && __FreeBSD_version < 800067
++/* Provide a stub getline() for older versions of FreeBSD. */
++static ssize_t getline(char **cp, size_t *lenp, FILE *f)
++{
++
++ if (*cp == NULL) {
++ *cp = malloc(4096);
++ *lenp = 4096;
++ }
++ if (fgets(*cp, *lenp, f) == NULL)
++ return (0);
++ return (strlen(*cp));
++}
++#endif
++
+ int parse_config_file(const char *fn)
+ {
+ FILE *f;
diff --git a/sysutils/mcelog/files/patch-eventloop.c b/sysutils/mcelog/files/patch-eventloop.c
new file mode 100644
index 000000000000..e9d47c4640cc
--- /dev/null
+++ b/sysutils/mcelog/files/patch-eventloop.c
@@ -0,0 +1,38 @@
+--- ./eventloop.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./eventloop.c 2011-10-14 22:36:47.000000000 -0400
+@@ -38,7 +38,9 @@
+ static struct pollfd pollfds[MAX_POLLFD];
+ static struct pollcb pollcbs[MAX_POLLFD];
+
++#ifdef __Linux__
+ static sigset_t event_sigs;
++#endif
+
+ static int closeonexec(int fd)
+ {
+@@ -97,6 +99,7 @@
+ }
+
+ /* Run signal handler only directly after event loop */
++#ifdef __Linux__
+ int event_signal(int sig)
+ {
+ static int first = 1;
+@@ -111,11 +114,17 @@
+ return -1;
+ return 0;
+ }
++#endif
+
+ void eventloop(void)
+ {
+ for (;;) {
++#ifdef __Linux__
+ int n = ppoll(pollfds, max_pollfd, NULL, &event_sigs);
++#endif
++#ifdef __FreeBSD__
++ int n = poll(pollfds, max_pollfd, -1);
++#endif
+ if (n <= 0) {
+ if (n < 0 && errno != EINTR)
+ SYSERRprintf("poll error");
diff --git a/sysutils/mcelog/files/patch-intel.c b/sysutils/mcelog/files/patch-intel.c
new file mode 100644
index 000000000000..50ba80932891
--- /dev/null
+++ b/sysutils/mcelog/files/patch-intel.c
@@ -0,0 +1,21 @@
+--- ./intel.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./intel.c 2011-10-14 22:36:47.000000000 -0400
+@@ -38,7 +38,7 @@
+ return CPU_CORE2;
+ else if (model == 0x1d)
+ return CPU_DUNNINGTON;
+- else if (model == 0x1a)
++ else if (model == 0x1a || model == 0x2c) /* Nehalem/Westmere */
+ return CPU_NEHALEM;
+
+ if (model >= 0x1a)
+@@ -79,7 +79,9 @@
+ corr_err_cnt = EXTRACT(m->status, 38, 52);
+ memory_error(m, channel, dimm, corr_err_cnt, recordlen);
+
++#ifdef __Linux__
+ account_page_error(m, channel, dimm, corr_err_cnt);
++#endif
+
+ return 1;
+ }
diff --git a/sysutils/mcelog/files/patch-mcelog.c b/sysutils/mcelog/files/patch-mcelog.c
new file mode 100644
index 000000000000..b70bdc8bc416
--- /dev/null
+++ b/sysutils/mcelog/files/patch-mcelog.c
@@ -0,0 +1,680 @@
+--- ./mcelog.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./mcelog.c 2011-10-14 22:37:22.000000000 -0400
+@@ -20,8 +20,21 @@
+ #define _GNU_SOURCE 1
+ #include <sys/fcntl.h>
+ #include <sys/ioctl.h>
++#ifdef __Linux__
+ #include <asm/types.h>
+ #include <asm/ioctls.h>
++#endif
++#ifdef __FreeBSD__
++#include <sys/types.h>
++#include <sys/sysctl.h>
++#include <machine/cpufunc.h>
++#include <machine/cputypes.h>
++#include <machine/specialreg.h>
++#include <err.h>
++#include <kvm.h>
++#include <limits.h>
++#endif
++#undef CPU_P4
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <string.h>
+@@ -57,9 +70,25 @@
+ #include "yellow.h"
+ #include "page.h"
+
++struct mca_record {
++ uint64_t mr_status;
++ uint64_t mr_addr;
++ uint64_t mr_misc;
++ uint64_t mr_tsc;
++ int mr_apic_id;
++ int mr_bank;
++ uint64_t mr_mcg_cap;
++ uint64_t mr_mcg_status;
++ int mr_cpu_id;
++ int mr_cpu_vendor_id;
++ int mr_cpu;
++};
++
+ enum cputype cputype = CPU_GENERIC;
+
++#ifdef __Linux__
+ char *logfn = LOG_DEV_FILENAME;
++#endif
+
+ int ignore_nodev;
+ int filter_bogus = 1;
+@@ -70,12 +99,18 @@
+ int dump_raw_ascii;
+ int daemon_mode;
+ static char *inputfile;
++#ifdef __Linux__
+ char *processor_flags;
++#endif
+ static int foreground;
+ int filter_memory_errors;
+ static struct config_cred runcred = { .uid = -1U, .gid = -1U };
+ static int numerrors;
+ static char *pidfile;
++#ifdef __FreeBSD__
++static char *execfile;
++static char *corefile;
++#endif
+
+ static void check_cpu(void);
+
+@@ -388,6 +423,7 @@
+ Wprintf("\n");
+ }
+
++#ifdef __Linux__
+ void check_cpu(void)
+ {
+ enum {
+@@ -455,7 +491,44 @@
+ } else
+ Eprintf("warning: Cannot open /proc/cpuinfo\n");
+ }
++#endif
++
++#ifdef __FreeBSD__
++void check_cpu(void)
++{
++ char vendor[20];
++ u_int regs[4];
++ u_int cpu_id;
++ int family, model;
++ static int checked;
++
++ if (checked)
++ return;
++ checked = 1;
++
++ do_cpuid(0, regs);
++ ((u_int *)vendor)[0] = regs[1];
++ ((u_int *)vendor)[1] = regs[3];
++ ((u_int *)vendor)[2] = regs[2];
++ vendor[12] = 0;
++
++ do_cpuid(1, regs);
++ cpu_id = regs[0];
++ family = CPUID_TO_FAMILY(cpu_id);
++ model = CPUID_TO_MODEL(cpu_id);
+
++ if (cpu_forced)
++ ;
++ else if (!strcmp(vendor,"AuthenticAMD") &&
++ (family == 15 || family == 16 || family == 17))
++ cputype = CPU_K8;
++ else if (!strcmp(vendor,"GenuineIntel"))
++ cputype = select_intel_cputype(family, model);
++ /* Add checks for other CPUs here */
++}
++#endif
++
++#ifdef __Linux__
+ static char *skipspace(char *s)
+ {
+ while (isspace(*s))
+@@ -479,6 +552,7 @@
+ }
+ return skipspace(s);
+ }
++#endif
+
+ static void dump_mce_final(struct mce *m, char *symbol, int missing, int recordlen,
+ int dseen)
+@@ -501,6 +575,7 @@
+ if (recordlen < endof_field(struct mce, f)) \
+ recordlen = endof_field(struct mce, f)
+
++#ifdef __Linux__
+ /* Decode ASCII input for fatal messages */
+ static void decodefatal(FILE *inf)
+ {
+@@ -646,6 +721,227 @@
+ if (data)
+ dump_mce_final(&m, symbol, missing, recordlen, disclaimer_seen);
+ }
++#endif
++
++#ifdef __FreeBSD__
++/*
++ * Table used to map cpuid vendor strings and FreeBSD CPU vendor IDs
++ * to Linux cpuvendor values.
++ */
++static struct {
++ char *name;
++ int vendor_id;
++ u_char cpuvendor;
++} vendor_ids[] = {
++ { "GenuineIntel", CPU_VENDOR_INTEL, 0 },
++ { "AuthenticAMD", CPU_VENDOR_AMD, 2 },
++ { "CentaurHauls", CPU_VENDOR_CENTAUR, 5 },
++#ifdef __i386__
++ { "CyrixInstead", CPU_VENDOR_CYRIX, 1 },
++ { "UMC UMC UMC ", CPU_VENDOR_UMC, 3 },
++ { "GenuineTMx86", CPU_VENDOR_TRANSMETA, 7 },
++ { "Geode by NSC", CPU_VENDOR_NSC, 8 },
++#endif
++};
++
++static int find_cpu_vendor(const char *vendor)
++{
++ u_int i;
++
++ for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
++ if (strcmp(vendor, vendor_ids[i].name) == 0)
++ return (vendor_ids[i].cpuvendor);
++ return (0xff);
++}
++
++static int find_cpu_vendor_id(const char *vendor)
++{
++ u_int i;
++
++ for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
++ if (strcmp(vendor, vendor_ids[i].name) == 0)
++ return (vendor_ids[i].vendor_id);
++ return (0);
++}
++
++static int map_cpu_vendor(int vendor_id)
++{
++ u_int i;
++
++ for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
++ if (vendor_ids[i].vendor_id == vendor_id)
++ return (vendor_ids[i].cpuvendor);
++ return (0xff);
++}
++
++/* Convert FreeBSD's struct mca_record into a struct mce. */
++static void convert_mca(struct mca_record *mr, struct mce *mce, int live,
++ size_t len)
++{
++ memset(mce, 0, sizeof(*mce));
++ mce->status = mr->mr_status;
++ mce->misc = mr->mr_misc;
++ mce->addr = mr->mr_addr;
++ mce->mcgstatus = mr->mr_mcg_status;
++ mce->tsc = mr->mr_tsc;
++ mce->cpuvendor = map_cpu_vendor(mr->mr_cpu_vendor_id);
++ mce->cpuid = mr->mr_cpu_id;
++ mce->bank = mr->mr_bank;
++ mce->finished = 1;
++ mce->extcpu = mr->mr_cpu;
++ mce->apicid = mr->mr_apic_id;
++ mce->mcgcap = mr->mr_mcg_cap;
++
++ /*
++ * For older live records (from sysctl), fill in some fields
++ * using registers from the current CPU.
++ */
++ if (len < offsetof(struct mca_record, mr_cpu_id) && live) {
++ char vendor[20];
++ u_int regs[4];
++
++ do_cpuid(0, regs);
++ ((u_int *)vendor)[0] = regs[1];
++ ((u_int *)vendor)[1] = regs[3];
++ ((u_int *)vendor)[2] = regs[2];
++ vendor[12] = 0;
++ mce->cpuvendor = find_cpu_vendor(vendor);
++
++ do_cpuid(1, regs);
++ mce->cpuid = regs[0];
++ }
++}
++
++/* Decode ASCII input for fatal messages */
++static void decodefatal(FILE *inf)
++{
++ struct mca_record mr;
++ struct mce m;
++ long long val, val2;
++ char *cp, line[100], *s, symbol[1];
++ const char *fmt;
++ int cpu, data, old, missing;
++ enum rows {
++ BANK = 0x1,
++ MCG = 0x2,
++ VENDOR = 0x4,
++ CPU = 0x8,
++ ADDR = 0x10,
++ MISC = 0x20,
++ };
++
++ symbol[0] = '\0';
++ data = 0;
++ missing = 0;
++ old = 0;
++ memset(&mr, 0, sizeof(mr));
++ while ((s = fgets(line, sizeof(line), inf)) != NULL) {
++ s = strstr(s, "MCA: ");
++ if (s == NULL)
++ continue;
++ s += strlen("MCA: ");
++
++ if (strncmp(s, "bank", 4) == 0 || strncmp(s, "Bank", 4) == 0) {
++ /* Start of a new record, dump the previous one. */
++ if (data != 0) {
++ /* Require some minimum data. */
++ if (data & BANK) {
++ if (mr.mr_status & MC_STATUS_ADDRV &&
++ !(data & ADDR))
++ missing = 1;
++ if (mr.mr_status & MC_STATUS_MISCV &&
++ !(data & MISC))
++ missing = 1;
++ convert_mca(&mr, &m, 0, sizeof(mr));
++ mce_cpuid(&m);
++ dump_mce_final(&m, symbol, missing,
++ sizeof(struct mce), 0);
++ }
++ data = 0;
++ missing = 0;
++ memset(&mr, 0, sizeof(mr));
++ }
++
++ if (s[0] == 'b') {
++ old = 1;
++ fmt = "bank %d, status 0x%llx";
++ } else {
++ old = 0;
++ fmt = "Bank %d, Status 0x%llx";
++ }
++ if (sscanf(s, fmt, &mr.mr_bank, &val) != 2)
++ missing = 1;
++ else {
++ data |= BANK;
++ mr.mr_status = val;
++ }
++ }
++ if (strncmp(s, "Global", 6) == 0) {
++ if (sscanf(s, "Global Cap 0x%llx, Status 0x%llx", &val,
++ &val2) != 2)
++ missing = 1;
++ else {
++ data |= MCG;
++ mr.mr_mcg_cap = val;
++ mr.mr_mcg_status = val2;
++ }
++ }
++ if (strncmp(s, "Vendor \"", 8) == 0) {
++ s += 8;
++ cp = index(s, '"');
++ if (cp != NULL) {
++ *cp = '\0';
++ mr.mr_cpu_vendor_id = find_cpu_vendor_id(s);
++ s = cp + 1;
++ if (sscanf(s, ", ID 0x%x, APIC ID %d",
++ &mr.mr_cpu_id, &mr.mr_apic_id) != 2)
++ missing = 1;
++ else
++ data |= VENDOR;
++ } else
++ missing = 1;
++ }
++ if (strncmp(s, "CPU", 3) == 0) {
++ if (sscanf(s, "CPU %d ", &cpu) != 1)
++ missing = 1;
++ else {
++ data |= CPU;
++ if (old)
++ mr.mr_apic_id = cpu;
++ else
++ mr.mr_cpu = cpu;
++ }
++ }
++ if (strncmp(s, "Address", 7) == 0) {
++ if (sscanf(s, "Address 0x%llx", &val) != 1)
++ missing = 1;
++ else {
++ data |= ADDR;
++ mr.mr_addr = val;
++ }
++ }
++ if (strncmp(s, "Misc", 4) == 0) {
++ if (sscanf(s, "Misc 0x%llx", &val) != 1)
++ missing = 1;
++ else {
++ data |= MISC;
++ mr.mr_misc = val;
++ }
++ }
++ }
++
++ /* Dump the last record. */
++ if (data & BANK) {
++ if (mr.mr_status & MC_STATUS_ADDRV && !(data & ADDR))
++ missing = 1;
++ if (mr.mr_status & MC_STATUS_MISCV && !(data & MISC))
++ missing = 1;
++ convert_mca(&mr, &m, 0, sizeof(mr));
++ mce_cpuid(&m);
++ dump_mce_final(&m, symbol, missing, sizeof(struct mce), 0);
++ }
++}
++#endif
+
+ static void remove_pidfile(void)
+ {
+@@ -686,6 +982,10 @@
+ " mcelog [options] --ascii < log\n"
+ " mcelog [options] --ascii --file log\n"
+ "Decode machine check ASCII output from kernel logs\n"
++#ifdef __FreeBSD__
++" mcelog [options] -M vmcore -N kernel\n"
++"Decode machine check error records from kernel crashdump.\n"
++#endif
+ "Options:\n"
+ "--cpu CPU Set CPU type CPU to decode (see below for valid types)\n"
+ "--cpumhz MHZ Set CPU Mhz to decode time (output unreliable, not needed on new kernels)\n"
+@@ -866,6 +1166,14 @@
+ case O_CONFIG_FILE:
+ /* parsed in config.c */
+ break;
++#ifdef __FreeBSD__
++ case 'M':
++ corefile = strdup(optarg);
++ break;
++ case 'N':
++ execfile = strdup(optarg);
++ break;
++#endif
+ case 0:
+ break;
+ default:
+@@ -900,8 +1208,10 @@
+
+ static void general_setup(void)
+ {
++#ifdef __Linux__
+ trigger_setup();
+ yellow_setup();
++#endif
+ config_cred("global", "run-credentials", &runcred);
+ if (config_bool("global", "filter-memory-errors") == 1)
+ filter_memory_errors = 1;
+@@ -924,6 +1234,7 @@
+ }
+ }
+
++#ifdef __Linux__
+ static void process(int fd, unsigned recordlen, unsigned loglen, char *buf)
+ {
+ int i;
+@@ -964,6 +1275,173 @@
+ if (finish)
+ exit(0);
+ }
++#endif
++
++#ifdef __FreeBSD__
++#ifdef LOCAL_HACK
++struct mca_record_old {
++ uint64_t mr_status;
++ uint64_t mr_addr;
++ uint64_t mr_misc;
++ uint64_t mr_tsc;
++ int mr_apic_id;
++ int mr_bank;
++};
++#endif
++
++struct mca_record_internal {
++ struct mca_record rec;
++ int logged;
++ STAILQ_ENTRY(mca_internal) link;
++};
++
++#ifdef LOCAL_HACK
++struct mca_record_internal_old {
++ struct mca_record_old rec;
++ int logged;
++ STAILQ_ENTRY(mca_internal) link;
++};
++#endif
++
++static struct nlist nl[] = {
++#define X_MCA_RECORDS 0
++ { .n_name = "_mca_records" },
++#ifdef LOCAL_HACK
++#define X_SNAPDATE 1
++ { .n_name = "_snapdate" },
++#endif
++ { .n_name = NULL },
++};
++
++static int
++kread(kvm_t *kvm, void *kvm_pointer, void *buf, size_t size, size_t offset)
++{
++ ssize_t ret;
++
++ ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, buf, size);
++ if (ret < 0 || (size_t)ret != size)
++ return (-1);
++ return (0);
++}
++
++static int
++kread_symbol(kvm_t *kvm, int index, void *buf, size_t size)
++{
++ ssize_t ret;
++
++ ret = kvm_read(kvm, nl[index].n_value, buf, size);
++ if (ret < 0 || (size_t)ret != size)
++ return (-1);
++ return (0);
++}
++
++static void process_kvm(const char *execfile, const char *corefile)
++{
++ struct mca_record mr, *mrp;
++ struct mce mce;
++ char errbuf[_POSIX2_LINE_MAX];
++ kvm_t *kvm;
++ size_t record_size, link_offset;
++ int i;
++#ifdef LOCAL_HACK
++ int snapdate;
++#endif
++
++ kvm = kvm_openfiles(execfile, corefile, NULL, O_RDONLY, errbuf);
++ if (kvm == NULL)
++ errx(1, "kvm_openfiles: %s", errbuf);
++ if (kvm_nlist(kvm, nl) != 0)
++ errx(1, "kvm_nlist: %s", kvm_geterr(kvm));
++
++#ifdef LOCAL_HACK
++ if (kread_symbol(kvm, X_SNAPDATE, &snapdate, sizeof(snapdate)) < 0)
++ errx(1, "kvm_read(snapdate) failed");
++#endif
++ /* stqh_first is the first pointer at this address. */
++ if (kread_symbol(kvm, X_MCA_RECORDS, &mrp, sizeof(mrp)) < 0)
++ errx(1, "kvm_read(mca_records) failed");
++#ifdef LOCAL_HACK
++ if (snapdate >= 20100329) {
++#endif
++ record_size = sizeof(struct mca_record);
++ link_offset = __offsetof(struct mca_record_internal,
++ link.stqe_next);
++#ifdef LOCAL_HACK
++ } else {
++ record_size = sizeof(struct mca_record_old);
++ link_offset = __offsetof(struct mca_record_internal_old,
++ link.stqe_next);
++ }
++#endif
++
++ for (i = 0; mrp != NULL; i++) {
++ memset(&mr, 0, sizeof(mr));
++ if (kread(kvm, mrp, &mr, record_size, 0) < 0)
++ break;
++ if (kread(kvm, mrp, &mrp, sizeof(mrp), link_offset) < 0)
++ mrp = NULL;
++
++ convert_mca(&mr, &mce, 1, record_size);
++ mce_prepare(&mce);
++ if (!mce_filter(&mce, sizeof(struct mce)))
++ continue;
++ if (!dump_raw_ascii) {
++ disclaimer();
++ Wprintf("MCE %d\n", i);
++ dump_mce(&mce, sizeof(struct mce));
++ } else
++ dump_mce_raw_ascii(&mce, sizeof(struct mce));
++ flushlog();
++ }
++
++ exit(0);
++}
++
++static void process_live(void)
++{
++ struct mca_record mr;
++ struct mce mce;
++ int mib[4];
++ size_t len;
++ int count, finish, i;
++
++ len = sizeof(count);
++ if (sysctlbyname("hw.mca.count", &count, &len, NULL, 0) < 0)
++ return;
++
++ len = 4;
++ if (sysctlnametomib("hw.mca.records", mib, &len) < 0)
++ return;
++
++ finish = 0;
++ for (i = 0; i < count; i++) {
++ mib[3] = i;
++ len = sizeof(mr);
++ memset(&mr, 0, sizeof(mr));
++ if (sysctl(mib, 4, &mr, &len, NULL, 0) < 0) {
++ warn("sysctl(hw.mca.records.%d)", i);
++ continue;
++ }
++
++ convert_mca(&mr, &mce, 1, len);
++ mce_prepare(&mce);
++ if (numerrors > 0 && --numerrors == 0)
++ finish = 1;
++ if (!mce_filter(&mce, sizeof(struct mce)))
++ continue;
++ if (!dump_raw_ascii) {
++ disclaimer();
++ Wprintf("MCE %d\n", i);
++ dump_mce(&mce, sizeof(struct mce));
++ } else
++ dump_mce_raw_ascii(&mce, sizeof(struct mce));
++ flushlog();
++ }
++
++ if (finish)
++ exit(0);
++}
++#endif
+
+ static void noargs(int ac, char **av)
+ {
+@@ -1022,22 +1500,30 @@
+ char *buf;
+ };
+
++#ifdef __Linux__
+ static void process_mcefd(struct pollfd *pfd, void *data)
+ {
+ struct mcefd_data *d = (struct mcefd_data *)data;
+ assert((pfd->revents & POLLIN) != 0);
+ process(pfd->fd, d->recordlen, d->loglen, d->buf);
+ }
++#endif
+
+ int main(int ac, char **av)
+ {
++#ifdef __Linux__
+ struct mcefd_data d = {};
+- int opt;
+ int fd;
++#endif
++ int opt;
+
+ parse_config(av);
+
+- while ((opt = getopt_long(ac, av, "", options, NULL)) != -1) {
++#ifdef __FreeBSD__
++ while ((opt = getopt_long(ac, av, "M:N:", options, NULL)) != -1) {
++#else
++ while ((opt = getopt_long(ac, av, "", options, NULL)) != -1) {
++#endif
+ if (opt == '?') {
+ usage();
+ } else if (combined_modifier(opt) > 0) {
+@@ -1057,13 +1543,21 @@
+ } else if (opt == 0)
+ break;
+ }
++#ifdef __Linux__
+ if (av[optind])
+ logfn = av[optind++];
++#endif
+ if (av[optind])
+ usage();
++#ifdef __FreeBSD__
++ if ((corefile != NULL) ^ (execfile != NULL) ||
++ (corefile != NULL && daemon_mode))
++ usage();
++#endif
+ checkdmi();
+ general_setup();
+
++#ifdef __Linux__
+ fd = open(logfn, O_RDONLY);
+ if (fd < 0) {
+ if (ignore_nodev)
+@@ -1078,24 +1572,39 @@
+ err("MCE_GET_LOG_LEN");
+
+ d.buf = xalloc(d.recordlen * d.loglen);
++#endif
+ if (daemon_mode) {
+ check_cpu();
+ prefill_memdb();
+ if (!do_dmi)
+ closedmi();
+ server_setup();
++#ifdef __Linux__
+ page_setup();
++#endif
+ drop_cred();
++#ifdef __Linux__
+ register_pollcb(fd, POLLIN, process_mcefd, &d);
++#endif
+ if (!foreground && daemon(0, need_stdout()) < 0)
+ err("daemon");
+ if (pidfile)
+ write_pidfile();
+ eventloop();
+ } else {
++#ifdef __Linux__
+ process(fd, d.recordlen, d.loglen, d.buf);
++#endif
++#ifdef __FreeBSD__
++ if (corefile != NULL)
++ process_kvm(execfile, corefile);
++ else
++ process_live();
++#endif
+ }
++#ifdef __Linux__
+ trigger_wait();
++#endif
+
+ exit(0);
+ }
diff --git a/sysutils/mcelog/files/patch-mcelog.h b/sysutils/mcelog/files/patch-mcelog.h
new file mode 100644
index 000000000000..7315be854410
--- /dev/null
+++ b/sysutils/mcelog/files/patch-mcelog.h
@@ -0,0 +1,25 @@
+--- ./mcelog.h.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./mcelog.h 2011-10-14 22:37:06.000000000 -0400
+@@ -64,9 +64,11 @@
+ #define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
+ #define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */
+
++#ifndef MCG_STATUS_RIPV
+ #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */
+ #define MCG_STATUS_EIPV (1ULL<<1) /* eip points to correct instruction */
+ #define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */
++#endif
+
+ #define MCG_CMCI_P (1ULL<<10) /* CMCI supported */
+ #define MCG_TES_P (1ULL<<11) /* Yellow bit cache threshold supported */
+@@ -89,6 +91,10 @@
+ #define PRINTFLIKE
+ #endif
+
++#if defined(__FreeBSD__) && defined(_STDIO_H_)
++FILE *open_memstream(char **cp, size_t *lenp);
++#endif
++
+ int Wprintf(char *fmt, ...) PRINTFLIKE;
+ void Eprintf(char *fmt, ...) PRINTFLIKE;
+ void SYSERRprintf(char *fmt, ...) PRINTFLIKE;
diff --git a/sysutils/mcelog/files/patch-memdb.c b/sysutils/mcelog/files/patch-memdb.c
new file mode 100644
index 000000000000..32024fb9e1b0
--- /dev/null
+++ b/sysutils/mcelog/files/patch-memdb.c
@@ -0,0 +1,12 @@
+--- ./memdb.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./memdb.c 2011-10-14 22:36:47.000000000 -0400
+@@ -170,7 +170,9 @@
+ asprintf(&env[ei++], "THRESHOLD_COUNT=%d", bucket->count + bucket->excess);
+ env[ei] = NULL;
+ assert(ei < MAX_ENV);
++#ifdef __Linux__
+ run_trigger(bc->trigger, NULL, env);
++#endif
+ for (i = 0; i < ei; i++)
+ free(env[i]);
+ out:
diff --git a/sysutils/mcelog/files/patch-p4.c b/sysutils/mcelog/files/patch-p4.c
new file mode 100644
index 000000000000..f512eb8d6658
--- /dev/null
+++ b/sysutils/mcelog/files/patch-p4.c
@@ -0,0 +1,13 @@
+--- ./p4.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./p4.c 2011-10-14 22:36:47.000000000 -0400
+@@ -175,8 +175,10 @@
+ Wprintf("%s CACHE %s %s Error\n", type, level,
+ get_RRRR_str((mca & CACHE_RRRR_MASK) >>
+ CACHE_RRRR_SHIFT));
++#ifdef __Linux__
+ if (track == 2)
+ run_yellow_trigger(cpu, typenum, levelnum, type, level, socket);
++#endif
+ } else if (test_prefix(10, mca)) {
+ if (mca == 0x400)
+ Wprintf("Internal Timer error\n");
diff --git a/sysutils/mcelog/files/patch-server.c b/sysutils/mcelog/files/patch-server.c
new file mode 100644
index 000000000000..372265eb3282
--- /dev/null
+++ b/sysutils/mcelog/files/patch-server.c
@@ -0,0 +1,79 @@
+--- ./server.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./server.c 2011-10-14 22:36:47.000000000 -0400
+@@ -101,7 +101,9 @@
+
+ static void dispatch_pages(FILE *fh)
+ {
++#ifdef __Linux__
+ dump_page_errors(fh);
++#endif
+ fprintf(fh, "done\n");
+ }
+
+@@ -137,6 +139,7 @@
+ Enomem();
+ }
+
++#ifdef __Linux__
+ /* check if client is allowed to access */
+ static int access_check(int fd, struct msghdr *msg)
+ {
+@@ -162,6 +165,35 @@
+ sendstring(fd, "permission denied\n");
+ return -1;
+ }
++#endif
++
++#ifdef __FreeBSD__
++/* check if client is allowed to access */
++static int access_check(int fd, struct msghdr *msg)
++{
++ struct cmsghdr *cmsg;
++ struct cmsgcred *cr;
++
++ /* check credentials */
++ cmsg = CMSG_FIRSTHDR(msg);
++ if (cmsg == NULL ||
++ cmsg->cmsg_level != SOL_SOCKET ||
++ cmsg->cmsg_type != SCM_CREDS) {
++ Eprintf("Did not receive credentials over client unix socket %p\n",
++ cmsg);
++ return -1;
++ }
++ cr = (struct cmsgcred *)CMSG_DATA(cmsg);
++ if (cr->cmcred_uid == 0 ||
++ (acc.uid != -1U && cr->cmcred_uid == acc.uid) ||
++ (acc.gid != -1U && cr->cmcred_gid == acc.gid))
++ return 0;
++ Eprintf("rejected client access from pid:%u uid:%u gid:%u\n",
++ cr->cmcred_pid, cr->cmcred_uid, cr->cmcred_gid);
++ sendstring(fd, "permission denied\n");
++ return -1;
++}
++#endif
+
+ /* retrieve commands from client */
+ static int client_input(int fd, struct clientcon *cc)
+@@ -242,18 +274,22 @@
+ {
+ struct clientcon *cc = NULL;
+ int nfd = accept(pfd->fd, NULL, 0);
++#ifdef __Linux__
+ int on;
++#endif
+
+ if (nfd < 0) {
+ SYSERRprintf("accept failed on client socket");
+ return;
+ }
+
++#ifdef __Linux__
+ on = 1;
+ if (setsockopt(nfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+ SYSERRprintf("Cannot enable credentials passing on client socket");
+ goto cleanup;
+ }
++#endif
+
+ cc = xalloc(sizeof(struct clientcon));
+ if (register_pollcb(nfd, POLLIN, client_event, cc) < 0) {
diff --git a/sysutils/mcelog/files/patch-tsc.c b/sysutils/mcelog/files/patch-tsc.c
new file mode 100644
index 000000000000..c035eb9850db
--- /dev/null
+++ b/sysutils/mcelog/files/patch-tsc.c
@@ -0,0 +1,95 @@
+--- ./tsc.c.orig 2009-12-15 07:18:40.000000000 -0500
++++ ./tsc.c 2011-10-14 22:36:47.000000000 -0400
+@@ -15,6 +15,12 @@
+ on your Linux system; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ #define _GNU_SOURCE 1
++#ifdef __FreeBSD__
++#include <sys/types.h>
++#include <sys/sysctl.h>
++#include <machine/cpufunc.h>
++#include <machine/specialreg.h>
++#endif
+ #include <string.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -46,6 +52,7 @@
+ return 0;
+ }
+
++#ifdef __Linux__
+ static double cpufreq_mhz(int cpu, double infomhz)
+ {
+ double mhz;
+@@ -68,12 +75,29 @@
+ fclose(f);
+ return mhz;
+ }
++#endif
++
++#ifdef __FreeBSD__
++static double cpufreq_mhz(int cpu, double infomhz)
++{
++ double mhz;
++ uint64_t freq;
++ size_t len;
++
++ len = sizeof(freq);
++ if (sysctlbyname("machdep.tsc_freq", &freq, &len, NULL, 0) < 0)
++ return infomhz;
++ mhz = freq / 1000000.0;
++ return mhz;
++}
++#endif
+
+ int decode_tsc_forced(char **buf, double mhz, u64 tsc)
+ {
+ return fmt_tsc(buf, tsc, mhz);
+ }
+
++#ifdef __Linux__
+ static int deep_sleep_states(int cpu)
+ {
+ int ret;
+@@ -132,6 +156,41 @@
+ return 0;
+ return 1;
+ }
++#endif
++
++#ifdef __FreeBSD__
++/* Try to figure out if this CPU has a somewhat reliable TSC clock */
++static int tsc_reliable(int cputype, int cpunum)
++{
++ u_int regs[4];
++ u_int cpu_id, amd_pminfo;
++
++ if (cputype != CPU_K8 && !is_intel_cpu(cputype))
++ return 0;
++
++ do_cpuid(0, regs);
++ cpu_id = regs[1];
++ do_cpuid(0x80000000, regs);
++ if (regs[0] >= 0x80000007) {
++ do_cpuid(0x80000007, regs);
++ amd_pminfo = regs[3];
++ } else
++ amd_pminfo = 0;
++
++ if (amd_pminfo & AMDPM_TSC_INVARIANT)
++ return 1;
++ if (is_intel_cpu(cputype)) {
++ if (CPUID_TO_FAMILY(cpu_id) >= 0x10 ||
++ cpu_id == 0x60fb2)
++ return 1;
++ } else if ((CPUID_TO_FAMILY(cpu_id) == 0x6 &&
++ CPUID_TO_MODEL(cpu_id) >= 0xe) ||
++ (CPUID_TO_FAMILY(cpu_id) == 0xf && CPUID_TO_MODEL(cpu_id) >= 0x3))
++ return 1;
++
++ return 0;
++}
++#endif
+
+ int decode_tsc_current(char **buf, int cpunum, enum cputype cputype, double mhz,
+ unsigned long long tsc)
diff --git a/sysutils/mcelog/pkg-descr b/sysutils/mcelog/pkg-descr
new file mode 100644
index 000000000000..53655b16adb8
--- /dev/null
+++ b/sysutils/mcelog/pkg-descr
@@ -0,0 +1,15 @@
+mcelog processes machine checks (in particular memory and CPU
+hardware errors) on modern x86-based unix systems and
+produces human-readable output.
+
+This software is heavily patched to work on FreeBSD systems,
+and thus provides an extremely limited subset of features as
+of this writing. The primary purpose is to provide a way to
+decode MCE output from the FreeBSD kernel into something more
+human-readable using the command 'mcelog --no-dmi --ascii'
+
+FreeBSD conversion patches were originally written by John
+Baldwin <jhb@freebsd.org> and later incorporated into this
+port.
+
+WWW: http://mcelog.org/
diff --git a/sysutils/mcelog/pkg-message b/sysutils/mcelog/pkg-message
new file mode 100644
index 000000000000..80710e89cfd8
--- /dev/null
+++ b/sysutils/mcelog/pkg-message
@@ -0,0 +1,7 @@
+=================================================
+You can decode MCE output from the FreeBSD kernel
+by using the following command:
+
+mcelog --no-dmi --ascii --file /path/to/log
+
+=================================================