17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <mach.h>
57dd7cddfSDavid du Colombier #include <ctype.h>
67dd7cddfSDavid du Colombier
74de34a7eSDavid du Colombier static int rtrace(uvlong, uvlong, uvlong);
84de34a7eSDavid du Colombier static int ctrace(uvlong, uvlong, uvlong);
94de34a7eSDavid du Colombier static int i386trace(uvlong, uvlong, uvlong);
1074f16c81SDavid du Colombier static int amd64trace(uvlong, uvlong, uvlong);
114de34a7eSDavid du Colombier static uvlong getval(uvlong);
127dd7cddfSDavid du Colombier static void inithdr(int);
137dd7cddfSDavid du Colombier static void fatal(char*, ...);
147dd7cddfSDavid du Colombier static void readstack(void);
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier static Fhdr fhdr;
177dd7cddfSDavid du Colombier static int interactive;
187dd7cddfSDavid du Colombier
197dd7cddfSDavid du Colombier #define FRAMENAME ".frame"
207dd7cddfSDavid du Colombier
217dd7cddfSDavid du Colombier static void
usage(void)227dd7cddfSDavid du Colombier usage(void)
237dd7cddfSDavid du Colombier {
247dd7cddfSDavid du Colombier fprint(2, "usage: ktrace [-i] kernel pc sp [link]\n");
257dd7cddfSDavid du Colombier exits("usage");
267dd7cddfSDavid du Colombier }
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier static void
printaddr(char * addr,uvlong pc)294de34a7eSDavid du Colombier printaddr(char *addr, uvlong pc)
307dd7cddfSDavid du Colombier {
317dd7cddfSDavid du Colombier int i;
327dd7cddfSDavid du Colombier char *p;
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier /*
357dd7cddfSDavid du Colombier * reformat the following.
367dd7cddfSDavid du Colombier *
377dd7cddfSDavid du Colombier * foo+1a1 -> src(foo+0x1a1);
387dd7cddfSDavid du Colombier * 10101010 -> src(0x10101010);
397dd7cddfSDavid du Colombier */
407dd7cddfSDavid du Colombier
417dd7cddfSDavid du Colombier if(strlen(addr) == 8 && strchr(addr, '+') == nil){
427dd7cddfSDavid du Colombier for(i=0; i<8; i++)
437dd7cddfSDavid du Colombier if(!isxdigit(addr[i]))
447dd7cddfSDavid du Colombier break;
457dd7cddfSDavid du Colombier if(i == 8){
4674f16c81SDavid du Colombier print("src(%#.8llux); // 0x%s\n", pc, addr);
477dd7cddfSDavid du Colombier return;
487dd7cddfSDavid du Colombier }
497dd7cddfSDavid du Colombier }
507dd7cddfSDavid du Colombier
517dd7cddfSDavid du Colombier if(p=strchr(addr, '+')){
527dd7cddfSDavid du Colombier *p++ = 0;
5374f16c81SDavid du Colombier print("src(%#.8llux); // %s+0x%s\n", pc, addr, p);
547dd7cddfSDavid du Colombier }else
5574f16c81SDavid du Colombier print("src(%#.8llux); // %s\n", pc, addr);
567dd7cddfSDavid du Colombier }
577dd7cddfSDavid du Colombier
584de34a7eSDavid du Colombier static void (*fmt)(char*, uvlong) = printaddr;
597dd7cddfSDavid du Colombier
607dd7cddfSDavid du Colombier void
main(int argc,char * argv[])617dd7cddfSDavid du Colombier main(int argc, char *argv[])
627dd7cddfSDavid du Colombier {
634de34a7eSDavid du Colombier int (*t)(uvlong, uvlong, uvlong);
644de34a7eSDavid du Colombier uvlong pc, sp, link;
657dd7cddfSDavid du Colombier int fd;
667dd7cddfSDavid du Colombier
677dd7cddfSDavid du Colombier ARGBEGIN{
687dd7cddfSDavid du Colombier case 'i':
697dd7cddfSDavid du Colombier interactive++;
707dd7cddfSDavid du Colombier break;
717dd7cddfSDavid du Colombier default:
727dd7cddfSDavid du Colombier usage();
737dd7cddfSDavid du Colombier }ARGEND
747dd7cddfSDavid du Colombier
757dd7cddfSDavid du Colombier link = 0;
767dd7cddfSDavid du Colombier t = ctrace;
777dd7cddfSDavid du Colombier switch(argc){
787dd7cddfSDavid du Colombier case 4:
797dd7cddfSDavid du Colombier t = rtrace;
804de34a7eSDavid du Colombier link = strtoull(argv[3], 0, 16);
817dd7cddfSDavid du Colombier break;
827dd7cddfSDavid du Colombier case 3:
837dd7cddfSDavid du Colombier break;
847dd7cddfSDavid du Colombier default:
857dd7cddfSDavid du Colombier usage();
867dd7cddfSDavid du Colombier }
874de34a7eSDavid du Colombier pc = strtoull(argv[1], 0, 16);
884de34a7eSDavid du Colombier sp = strtoull(argv[2], 0, 16);
897dd7cddfSDavid du Colombier if(!interactive)
907dd7cddfSDavid du Colombier readstack();
917dd7cddfSDavid du Colombier
927dd7cddfSDavid du Colombier fd = open(argv[0], OREAD);
937dd7cddfSDavid du Colombier if(fd < 0)
947dd7cddfSDavid du Colombier fatal("can't open %s: %r", argv[0]);
957dd7cddfSDavid du Colombier inithdr(fd);
9680ee5cbfSDavid du Colombier switch(fhdr.magic){
9780ee5cbfSDavid du Colombier case I_MAGIC: /* intel 386 */
987dd7cddfSDavid du Colombier t = i386trace;
9980ee5cbfSDavid du Colombier break;
10074f16c81SDavid du Colombier case S_MAGIC: /* amd64 */
10174f16c81SDavid du Colombier t = amd64trace;
10274f16c81SDavid du Colombier break;
10380ee5cbfSDavid du Colombier case A_MAGIC: /* 68020 */
10480ee5cbfSDavid du Colombier case J_MAGIC: /* intel 960 */
10580ee5cbfSDavid du Colombier t = ctrace;
10680ee5cbfSDavid du Colombier break;
10780ee5cbfSDavid du Colombier case K_MAGIC: /* sparc */
10880ee5cbfSDavid du Colombier case D_MAGIC: /* amd 29000 */
10980ee5cbfSDavid du Colombier case V_MAGIC: /* mips 3000 */
11080ee5cbfSDavid du Colombier case M_MAGIC: /* mips 4000 */
11180ee5cbfSDavid du Colombier case E_MAGIC: /* arm 7-something */
11280ee5cbfSDavid du Colombier case Q_MAGIC: /* powerpc */
11380ee5cbfSDavid du Colombier case N_MAGIC: /* mips 4000 LE */
11480ee5cbfSDavid du Colombier case L_MAGIC: /* dec alpha */
11580ee5cbfSDavid du Colombier t = rtrace;
11680ee5cbfSDavid du Colombier break;
11780ee5cbfSDavid du Colombier case X_MAGIC: /* att dsp 3210 */
118*14cc0f53SDavid du Colombier sysfatal("can't ktrace %s", argv[0]);
11980ee5cbfSDavid du Colombier break;
12080ee5cbfSDavid du Colombier default:
12180ee5cbfSDavid du Colombier fprint(2, "%s: warning: can't tell what type of stack %s uses; assuming it's %s\n",
12280ee5cbfSDavid du Colombier argv0, argv[0], argc == 4 ? "risc" : "cisc");
12380ee5cbfSDavid du Colombier break;
12480ee5cbfSDavid du Colombier }
1257dd7cddfSDavid du Colombier (*t)(pc, sp, link);
1267dd7cddfSDavid du Colombier exits(0);
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier
1297dd7cddfSDavid du Colombier static void
inithdr(int fd)1307dd7cddfSDavid du Colombier inithdr(int fd)
1317dd7cddfSDavid du Colombier {
1327dd7cddfSDavid du Colombier seek(fd, 0, 0);
1337dd7cddfSDavid du Colombier if(!crackhdr(fd, &fhdr))
1347dd7cddfSDavid du Colombier fatal("read text header");
1357dd7cddfSDavid du Colombier
1367dd7cddfSDavid du Colombier if(syminit(fd, &fhdr) < 0)
1377dd7cddfSDavid du Colombier fatal("%r\n");
1387dd7cddfSDavid du Colombier }
1397dd7cddfSDavid du Colombier
1407dd7cddfSDavid du Colombier static int
rtrace(uvlong pc,uvlong sp,uvlong link)1414de34a7eSDavid du Colombier rtrace(uvlong pc, uvlong sp, uvlong link)
1427dd7cddfSDavid du Colombier {
1437dd7cddfSDavid du Colombier Symbol s, f;
1447dd7cddfSDavid du Colombier char buf[128];
1454de34a7eSDavid du Colombier uvlong oldpc;
1467dd7cddfSDavid du Colombier int i;
1477dd7cddfSDavid du Colombier
1487dd7cddfSDavid du Colombier i = 0;
1497dd7cddfSDavid du Colombier while(findsym(pc, CTEXT, &s)) {
1507dd7cddfSDavid du Colombier if(pc == s.value) /* at first instruction */
1517dd7cddfSDavid du Colombier f.value = 0;
1527dd7cddfSDavid du Colombier else if(findlocal(&s, FRAMENAME, &f) == 0)
1537dd7cddfSDavid du Colombier break;
1547dd7cddfSDavid du Colombier
1557dd7cddfSDavid du Colombier symoff(buf, sizeof buf, pc, CANY);
1569a747e4fSDavid du Colombier fmt(buf, pc);
1577dd7cddfSDavid du Colombier
1587dd7cddfSDavid du Colombier oldpc = pc;
15980ee5cbfSDavid du Colombier if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant){
16080ee5cbfSDavid du Colombier if(link == 0)
16180ee5cbfSDavid du Colombier fprint(2, "%s: need to supply a valid link register\n", argv0);
1627dd7cddfSDavid du Colombier pc = link;
16380ee5cbfSDavid du Colombier }else{
1647dd7cddfSDavid du Colombier pc = getval(sp);
1657dd7cddfSDavid du Colombier if(pc == 0)
1667dd7cddfSDavid du Colombier break;
1677dd7cddfSDavid du Colombier }
1687dd7cddfSDavid du Colombier
1697dd7cddfSDavid du Colombier if(pc == 0 || (pc == oldpc && f.value == 0))
1707dd7cddfSDavid du Colombier break;
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier sp += f.value;
1737dd7cddfSDavid du Colombier
1747dd7cddfSDavid du Colombier if(++i > 40)
1757dd7cddfSDavid du Colombier break;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier return i;
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier static int
ctrace(uvlong pc,uvlong sp,uvlong link)1814de34a7eSDavid du Colombier ctrace(uvlong pc, uvlong sp, uvlong link)
1827dd7cddfSDavid du Colombier {
1837dd7cddfSDavid du Colombier Symbol s;
1847dd7cddfSDavid du Colombier char buf[128];
1857dd7cddfSDavid du Colombier int found;
1864de34a7eSDavid du Colombier uvlong opc, moved;
1874de34a7eSDavid du Colombier long j;
1887dd7cddfSDavid du Colombier
1897dd7cddfSDavid du Colombier USED(link);
1907dd7cddfSDavid du Colombier j = 0;
1917dd7cddfSDavid du Colombier opc = 0;
1927dd7cddfSDavid du Colombier while(pc && opc != pc) {
1937dd7cddfSDavid du Colombier moved = pc2sp(pc);
1944de34a7eSDavid du Colombier if (moved == ~0){
19574f16c81SDavid du Colombier print("pc2sp(%#.8llux) = -1 %r\n", pc);
1967dd7cddfSDavid du Colombier break;
1977dd7cddfSDavid du Colombier }
1987dd7cddfSDavid du Colombier found = findsym(pc, CTEXT, &s);
1997dd7cddfSDavid du Colombier if (!found){
2007dd7cddfSDavid du Colombier print("findsym fails\n");
2017dd7cddfSDavid du Colombier break;
2027dd7cddfSDavid du Colombier }
2037dd7cddfSDavid du Colombier symoff(buf, sizeof buf, pc, CANY);
2049a747e4fSDavid du Colombier fmt(buf, pc);
2057dd7cddfSDavid du Colombier
2067dd7cddfSDavid du Colombier sp += moved;
2077dd7cddfSDavid du Colombier opc = pc;
2087dd7cddfSDavid du Colombier pc = getval(sp);
2097dd7cddfSDavid du Colombier if(pc == 0)
2107dd7cddfSDavid du Colombier break;
2117dd7cddfSDavid du Colombier sp += mach->szaddr; /*assumes address size = stack width*/
2127dd7cddfSDavid du Colombier if(++j > 40)
2137dd7cddfSDavid du Colombier break;
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier return j;
2167dd7cddfSDavid du Colombier }
2177dd7cddfSDavid du Colombier
2187dd7cddfSDavid du Colombier static int
i386trace(uvlong pc,uvlong sp,uvlong link)2194de34a7eSDavid du Colombier i386trace(uvlong pc, uvlong sp, uvlong link)
2207dd7cddfSDavid du Colombier {
2217dd7cddfSDavid du Colombier int i;
2224de34a7eSDavid du Colombier uvlong osp;
2237dd7cddfSDavid du Colombier Symbol s, f;
2247dd7cddfSDavid du Colombier char buf[128];
2257dd7cddfSDavid du Colombier
2267dd7cddfSDavid du Colombier USED(link);
2277dd7cddfSDavid du Colombier i = 0;
2287dd7cddfSDavid du Colombier osp = 0;
2297dd7cddfSDavid du Colombier while(findsym(pc, CTEXT, &s)) {
2307dd7cddfSDavid du Colombier
2317dd7cddfSDavid du Colombier symoff(buf, sizeof buf, pc, CANY);
2329a747e4fSDavid du Colombier fmt(buf, pc);
2337dd7cddfSDavid du Colombier
2344de34a7eSDavid du Colombier //XXX s.value &= ~(uintptr)0;
2357dd7cddfSDavid du Colombier if(pc != s.value) { /* not at first instruction */
2367dd7cddfSDavid du Colombier if(findlocal(&s, FRAMENAME, &f) == 0)
2377dd7cddfSDavid du Colombier break;
2387dd7cddfSDavid du Colombier sp += f.value-mach->szaddr;
2399a747e4fSDavid du Colombier }else if(strcmp(s.name, "forkret") == 0){
2404de34a7eSDavid du Colombier //XXX
24174f16c81SDavid du Colombier print("//passing interrupt frame; last pc found at sp=%#llux\n", osp);
2424de34a7eSDavid du Colombier
2439a747e4fSDavid du Colombier sp += 15 * mach->szaddr; /* pop interrupt frame */
2447dd7cddfSDavid du Colombier }
2457dd7cddfSDavid du Colombier
2467dd7cddfSDavid du Colombier pc = getval(sp);
2474de34a7eSDavid du Colombier //XXX
2489a747e4fSDavid du Colombier if(pc == 0 && strcmp(s.name, "forkret") == 0){
2499a747e4fSDavid du Colombier sp += 3 * mach->szaddr; /* pop iret eip, cs, eflags */
25074f16c81SDavid du Colombier print("//guessing call through invalid pointer, try again at sp=%#llux\n", sp);
2519a747e4fSDavid du Colombier s.name = "";
2529a747e4fSDavid du Colombier pc = getval(sp);
2539a747e4fSDavid du Colombier }
2549a747e4fSDavid du Colombier if(pc == 0) {
25574f16c81SDavid du Colombier print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp);
2567dd7cddfSDavid du Colombier break;
2579a747e4fSDavid du Colombier }
2589a747e4fSDavid du Colombier osp = sp;
2597dd7cddfSDavid du Colombier
2607dd7cddfSDavid du Colombier sp += mach->szaddr;
2614de34a7eSDavid du Colombier //XXX
2629a747e4fSDavid du Colombier if(strcmp(s.name, "forkret") == 0)
2639a747e4fSDavid du Colombier sp += 2 * mach->szaddr; /* pop iret cs, eflags */
2647dd7cddfSDavid du Colombier
2657dd7cddfSDavid du Colombier if(++i > 40)
2667dd7cddfSDavid du Colombier break;
2677dd7cddfSDavid du Colombier }
2687dd7cddfSDavid du Colombier return i;
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier
27174f16c81SDavid du Colombier static int
amd64trace(uvlong pc,uvlong sp,uvlong link)27274f16c81SDavid du Colombier amd64trace(uvlong pc, uvlong sp, uvlong link)
27374f16c81SDavid du Colombier {
27474f16c81SDavid du Colombier int i, isintrr;
27574f16c81SDavid du Colombier uvlong osp;
27674f16c81SDavid du Colombier Symbol s, f;
27774f16c81SDavid du Colombier char buf[128];
27874f16c81SDavid du Colombier
27974f16c81SDavid du Colombier USED(link);
28074f16c81SDavid du Colombier i = 0;
28174f16c81SDavid du Colombier osp = 0;
28274f16c81SDavid du Colombier while(findsym(pc, CTEXT, &s)) {
28374f16c81SDavid du Colombier
28474f16c81SDavid du Colombier symoff(buf, sizeof buf, pc, CANY);
28574f16c81SDavid du Colombier fmt(buf, pc);
28674f16c81SDavid du Colombier
28774f16c81SDavid du Colombier if(strcmp(s.name, "_intrr") == 0)
28874f16c81SDavid du Colombier isintrr = 1;
28974f16c81SDavid du Colombier else
29074f16c81SDavid du Colombier isintrr = 0;
29174f16c81SDavid du Colombier if(pc != s.value) { /* not at first instruction */
29274f16c81SDavid du Colombier if(findlocal(&s, FRAMENAME, &f) == 0)
29374f16c81SDavid du Colombier break;
29474f16c81SDavid du Colombier sp += f.value-mach->szaddr;
29574f16c81SDavid du Colombier }
29674f16c81SDavid du Colombier else if(isintrr){
29774f16c81SDavid du Colombier print("//passing interrupt frame; last pc found at sp=%#llux\n", osp);
29874f16c81SDavid du Colombier /*
29974f16c81SDavid du Colombier * Pop interrupt frame (ureg.h) up to the IP value.
30074f16c81SDavid du Colombier */
30174f16c81SDavid du Colombier sp += 19 * mach->szaddr;
30274f16c81SDavid du Colombier }
30374f16c81SDavid du Colombier
30474f16c81SDavid du Colombier pc = getval(sp);
30574f16c81SDavid du Colombier if(pc == 0 && isintrr){
30674f16c81SDavid du Colombier /*
30774f16c81SDavid du Colombier * Pop IP, CS and FLAGS to get to the SP.
30874f16c81SDavid du Colombier * The AMD64 aligns the interrupt stack on
30974f16c81SDavid du Colombier * a 16-byte boundary so have the get the
31074f16c81SDavid du Colombier * SP from the saved frame.
31174f16c81SDavid du Colombier */
31274f16c81SDavid du Colombier sp += 3 * mach->szaddr;
31374f16c81SDavid du Colombier print("//guessing call through invalid pointer; try again at sp=%#llux\n", sp);
31474f16c81SDavid du Colombier s.name = "";
31574f16c81SDavid du Colombier sp = getval(sp);
31674f16c81SDavid du Colombier pc = getval(sp);
31774f16c81SDavid du Colombier }
31874f16c81SDavid du Colombier if(pc == 0) {
31974f16c81SDavid du Colombier print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp);
32074f16c81SDavid du Colombier break;
32174f16c81SDavid du Colombier }
32274f16c81SDavid du Colombier osp = sp;
32374f16c81SDavid du Colombier
32474f16c81SDavid du Colombier if(!isintrr)
32574f16c81SDavid du Colombier sp += mach->szaddr;
32674f16c81SDavid du Colombier
32774f16c81SDavid du Colombier if(++i > 40)
32874f16c81SDavid du Colombier break;
32974f16c81SDavid du Colombier }
33074f16c81SDavid du Colombier return i;
33174f16c81SDavid du Colombier }
33274f16c81SDavid du Colombier
3337dd7cddfSDavid du Colombier int naddr;
3344de34a7eSDavid du Colombier uvlong addr[1024];
3354de34a7eSDavid du Colombier uvlong val[1024];
3367dd7cddfSDavid du Colombier
3377dd7cddfSDavid du Colombier static void
putval(uvlong a,uvlong v)3384de34a7eSDavid du Colombier putval(uvlong a, uvlong v)
3397dd7cddfSDavid du Colombier {
3407dd7cddfSDavid du Colombier if(naddr < nelem(addr)){
3417dd7cddfSDavid du Colombier addr[naddr] = a;
3427dd7cddfSDavid du Colombier val[naddr] = v;
3437dd7cddfSDavid du Colombier naddr++;
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier static void
readstack(void)3487dd7cddfSDavid du Colombier readstack(void)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier Biobuf b;
3517dd7cddfSDavid du Colombier char *p;
3527dd7cddfSDavid du Colombier char *f[64];
3537dd7cddfSDavid du Colombier int nf, i;
3547dd7cddfSDavid du Colombier
3557dd7cddfSDavid du Colombier Binit(&b, 0, OREAD);
3567dd7cddfSDavid du Colombier while(p=Brdline(&b, '\n')){
3577dd7cddfSDavid du Colombier p[Blinelen(&b)-1] = 0;
3587dd7cddfSDavid du Colombier nf = tokenize(p, f, nelem(f));
3597dd7cddfSDavid du Colombier for(i=0; i<nf; i++){
3607dd7cddfSDavid du Colombier if(p=strchr(f[i], '=')){
3617dd7cddfSDavid du Colombier *p++ = 0;
3624de34a7eSDavid du Colombier putval(strtoull(f[i], 0, 16), strtoull(p, 0, 16));
3637dd7cddfSDavid du Colombier }
3647dd7cddfSDavid du Colombier }
3657dd7cddfSDavid du Colombier }
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier
3684de34a7eSDavid du Colombier static uvlong
getval(uvlong a)3694de34a7eSDavid du Colombier getval(uvlong a)
3707dd7cddfSDavid du Colombier {
3717dd7cddfSDavid du Colombier char buf[256];
3727dd7cddfSDavid du Colombier int i, n;
37374f16c81SDavid du Colombier uvlong r;
3747dd7cddfSDavid du Colombier
3757dd7cddfSDavid du Colombier if(interactive){
37674f16c81SDavid du Colombier print("// data at %#8.8llux? ", a);
3777dd7cddfSDavid du Colombier n = read(0, buf, sizeof(buf)-1);
3787dd7cddfSDavid du Colombier if(n <= 0)
3797dd7cddfSDavid du Colombier return 0;
3807dd7cddfSDavid du Colombier buf[n] = '\0';
38174f16c81SDavid du Colombier r = strtoull(buf, 0, 16);
3827dd7cddfSDavid du Colombier }else{
38374f16c81SDavid du Colombier r = 0;
3847dd7cddfSDavid du Colombier for(i=0; i<naddr; i++)
3857dd7cddfSDavid du Colombier if(addr[i] == a)
38674f16c81SDavid du Colombier r = val[i];
3877dd7cddfSDavid du Colombier }
38874f16c81SDavid du Colombier
38974f16c81SDavid du Colombier return r;
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier
3927dd7cddfSDavid du Colombier static void
fatal(char * fmt,...)3937dd7cddfSDavid du Colombier fatal(char *fmt, ...)
3947dd7cddfSDavid du Colombier {
3957dd7cddfSDavid du Colombier char buf[4096];
3967dd7cddfSDavid du Colombier va_list arg;
3977dd7cddfSDavid du Colombier
3987dd7cddfSDavid du Colombier va_start(arg, fmt);
3999a747e4fSDavid du Colombier vseprint(buf, buf+sizeof(buf), fmt, arg);
4007dd7cddfSDavid du Colombier va_end(arg);
4017dd7cddfSDavid du Colombier fprint(2, "ktrace: %s\n", buf);
4027dd7cddfSDavid du Colombier exits(buf);
4037dd7cddfSDavid du Colombier }
404