diff options
Diffstat (limited to 'web/l19.txt')
-rw-r--r-- | web/l19.txt | 1412 |
1 files changed, 1412 insertions, 0 deletions
diff --git a/web/l19.txt b/web/l19.txt new file mode 100644 index 0000000..af9d0bb --- /dev/null +++ b/web/l19.txt @@ -0,0 +1,1412 @@ +-- front +6.828 Shells Lecture + +Hello. + +-- intro +Bourne shell + +Simplest shell: run cmd arg arg ... + fork + exec in child + wait in parent + +More functionality: + file redirection: cmd >file + open file as fd 1 in child before exec + +Still more functionality: + pipes: cmd | cmd | cmd ... + create pipe, + run first cmd with pipe on fd 1, + run second cmd with other end of pipe on fd 0 + +More Bourne arcana: + $* - command args + "$@" - unexpanded command args + environment variables + macro substitution + if, while, for + || + && + "foo $x" + 'foo $x' + `cat foo` + +-- rc +Rc Shell + + +No reparsing of input (except explicit eval). + +Variables as explicit lists. + +Explicit concatenation. + +Multiple input pipes <{cmd} - pass /dev/fd/4 as file name. + +Syntax more like C, less like Algol. + +diff <{echo hi} <{echo bye} + +-- es +Es shell + + +rc++ + +Goal is to override functionality cleanly. + +Rewrite input like cmd | cmd2 as %pipe {cmd} {cmd2}. + +Users can redefine %pipe, etc. + +Need lexical scoping and let to allow new %pipe refer to old %pipe. + +Need garbage collection to collect unreachable code. + +Design principle: + minimal functionality + good defaults + allow users to customize implementations + + emacs, exokernel + +-- apps +Applications + +Shell scripts are only as good as the programs they use. + (What good are pipes without cat, grep, sort, wc, etc.?) + +The more the scripts can access, the more powerful they become. + +-- acme +Acme, Plan 9 text editor + +Make window system control files available to +everything, including shell. + +Can write shell scripts to script interactions. + +/home/rsc/bin/Slide +/home/rsc/bin/Slide- +/home/rsc/bin/Slide+ + +/usr/local/plan9/bin/adict + +win + +-- javascript +JavaScript + +Very powerful + - not because it's a great language + - because it has a great data set + - Google Maps + - Gmail + - Ymail + - etc. + +-- greasemonkey +GreaseMonkey + +// ==UserScript== +// @name Google Ring +// @namespace http://swtch.com/greasemonkey/ +// @description Changes Google Logo +// @include http://*.google.*/* +// ==/UserScript== + +(function() { + for(var i=0; i<document.images.length; i++){ + if(document.images[i].src == "http://www.google.com/intl/en/images/logo.gif") + document.images[i].src = "http://swtch.com/googlering.png"; + } +})(); + +-- webscript0 +Webscript + +Why can't I script my web interactions? + +/home/rsc/plan9/bin/rc/fedex + +webscript /home/rsc/src/webscript/a3 + /home/rsc/src/webscript/a2 + +-- acid +Acid, a programmable (scriptable) debugger + +defn stopped(pid) +{ + pfixstop(pid); + pstop(pid); +} + +defn pfixstop(pid) +{ + if *fmt(*PC-1, 'b') == 0xCC then { + // Linux stops us after the breakpoint, not at it + *PC = *PC-1; + } +} + +/usr/local/plan9/acid/port:/^defn.bpset +/usr/local/plan9/acid/port:/^defn.step + +defn checkpdb(pdb) +{ + loop 1,768 do { + if *pdb != 0 then { print(pdb\X, " ", *pdb\X, "\n"); } + pdb = pdb +4; + } +} + +-- guis +GUIs + +Can we script guis? Not as clear. + +Acme examples show one way: + turn events into file (pipe) to read. + +Tcl/tk is close too. + +Eventually everyone turns to C. + +-- others +Honorable Mentions + +Scheme + +Lisp + +AutoCAD + +Viaweb RTML + +-- c +"Real" programming languages vs. Scripts + +Why does everyone eventually rewrite scripts in C? + (aka C++, C#, any compiled language) + +What do you need C for now? + +How could you make it accessible to a script language? + +-- /home/rsc/bin/Slide +#!/usr/local/plan9/bin/rc + +echo name `{pwd}^/$1 | 9p write acme/$winid/ctl +echo clean | 9p write acme/$winid/ctl +echo get | 9p write acme/$winid/ctl + +-- /home/rsc/bin/Slide- +#!/usr/local/plan9/bin/rc + +name=$% +current=`{basename $name} +currentx=`{9 grep -n '^'$current'([ ]|$)' index | sed 's/:.*//'} + +pagex=`{echo $currentx - 1 | hoc} +if(~ $pagex 0){ + echo no such page + exit 0 +} +page=`{sed -n $pagex^p index | awk '{print $1}'} +if(~ $#page 0){ + echo no such page + exit 0 +} + +Slide $page +-- /home/rsc/bin/Slide+ +#!/usr/local/plan9/bin/rc + +name=$% +current=`{basename $name} +currentx=`{9 grep -n '^'$current'([ ]|$)' index | sed 's/:.*//'} + +pagex=`{echo $currentx + 1 | hoc} +page=`{sed -n $pagex^p index | awk '{print $1}'} +if(~ $#page 0){ + echo no such page + exit 0 +} + +Slide $page +-- /usr/local/plan9/bin/adict +#!/usr/local/plan9/bin/rc + +. 9.rc +. $PLAN9/lib/acme.rc + +fn event { + # $1 - c1 origin of event + # $2 - c2 type of action + # $3 - q0 beginning of selection + # $4 - q1 end of selection + # $5 - eq0 beginning of expanded selection + # $6 - eq1 end of expanded selection + # $7 - flag + # $8 - nr number of runes in $7 + # $9 - text + # $10 - chorded argument + # $11 - origin of chorded argument + + switch($1$2){ + case E* # write to body or tag + case F* # generated by ourselves; ignore + case K* # type away we do not care + case Mi # mouse: text inserted in tag + case MI # mouse: text inserted in body + case Md # mouse: text deleted from tag + case MD # mouse: text deleted from body + + case Mx MX # button 2 in tag or body + winwriteevent $* + + case Ml ML # button 3 in tag or body + { + if(~ $dict NONE) + dictwin /adict/$9/ $9 + if not + dictwin /adict/$dict/$9 $dict $9 + } & + } +} + +fn dictwin { + newwindow + winname $1 + switch($#*){ + case 1 + dict -d '?' >[2=1] | sed 1d | winwrite body + case 2 + dict=$2 + case 3 + dict=$2 + dict -d $dict $3 >[2=1] | winwrite body + } + winctl clean + wineventloop +} + +dict=NONE +if(~ $1 -d){ + shift + dict=$2 + shift +} +if(~ $1 -d*){ + dict=`{echo $1 | sed 's/-d//'} + shift +} +if(~ $1 -*){ + echo 'usage: adict [-d dict] [word...]' >[1=2] + exit usage +} + +switch($#*){ +case 0 + if(~ $dict NONE) + dictwin /adict/ + if not + dictwin /adict/$dict/ $dict +case * + if(~ $dict NONE){ + dict=`{dict -d'?' | 9 sed -n 's/^ ([^\[ ]+).*/\1/p' | sed 1q} + if(~ $#dict 0){ + echo 'no dictionaries present on this system' >[1=2] + exit nodict + } + } + for(i) + dictwin /adict/$dict/$i $dict $i +} + +-- /usr/local/plan9/lib/acme.rc +fn newwindow { + winctl=`{9p read acme/new/ctl} + winid=$winctl(1) + winctl noscroll +} + +fn winctl { + echo $* | 9p write acme/acme/$winid/ctl +} + +fn winread { + 9p read acme/acme/$winid/$1 +} + +fn winwrite { + 9p write acme/acme/$winid/$1 +} + +fn windump { + if(! ~ $1 - '') + winctl dumpdir $1 + if(! ~ $2 - '') + winctl dump $2 +} + +fn winname { + winctl name $1 +} + +fn winwriteevent { + echo $1$2$3 $4 | winwrite event +} + +fn windel { + if(~ $1 sure) + winctl delete + if not + winctl del +} + +fn wineventloop { + . <{winread event >[2]/dev/null | acmeevent} +} +-- /home/rsc/plan9/rc/bin/fedex +#!/bin/rc + +if(! ~ $#* 1) { + echo usage: fedex 123456789012 >[1=2] + exit usage +} + +rfork e + +fn bgrep{ +pattern=`{echo $1 | sed 's;/;\\&;'} +shift + +@{ echo 'X { +$ +a + +. +} +X ,x/(.+\n)+\n/ g/'$pattern'/p' | +sam -d $* >[2]/dev/null +} +} + +fn awk2 { + awk 'NR%2==1 { a=$0; } + NR%2==0 { b=$0; printf("%-30s %s\n", a, b); } + ' $* +} + +fn awk3 { + awk '{line[NR] = $0} + END{ + i = 4; + while(i < NR){ + what=line[i++]; + when=line[i]; + comment=""; + if(!(when ~ /..\/..\/.... ..:../)){ + # out of sync + printf("%s\n", what); + continue; + } + i++; + if(!(line[i+1] ~ /..\/..\/.... ..:../) && + (i+2 > NR || line[i+2] ~ /..\/..\/.... ..:../)){ + what = what ", " line[i++]; + } + printf("%s %s\n", when, what); + } + }' $* +} + +# hget 'http://www.fedex.com/cgi-bin/track_it?airbill_list='$1'&kurrent_airbill='$1'&language=english&cntry_code=us&state=0' | +hget 'http://www.fedex.com/cgi-bin/tracking?action=track&language=english&cntry_code=us&initial=x&mps=y&tracknumbers='$1 | + htmlfmt >/tmp/fedex.$pid +sed -n '/Tracking number/,/^$/p' /tmp/fedex.$pid | awk2 +echo +sed -n '/Reference number/,/^$/p' /tmp/fedex.$pid | awk2 +echo +sed -n '/Date.time/,/^$/p' /tmp/fedex.$pid | sed 1,4d | fmt -l 4000 | sed 's/ [A-Z][A-Z] /&\n/g' +rm /tmp/fedex.$pid +-- /home/rsc/src/webscript/a3 +#!./o.webscript + +load "http://www.ups.com/WebTracking/track?loc=en_US" +find textbox "InquiryNumber1" +input "1z30557w0340175623" +find next checkbox +input "yes" +find prev form +submit +if(find "Delivery Information"){ + find outer table + print +}else if(find "One or more"){ + print +}else{ + print "Unexpected results." + find page + print +} +-- /home/rsc/src/webscript/a2 +#load "http://apc-reset/outlets.htm" +load "apc.html" +print +print "\n=============\n" +find "yoshimi" +find outer row +find next select +input "Immediate Reboot" +submit +print +-- /usr/local/plan9/acid/port +// portable acid for all architectures + +defn pfl(addr) +{ + print(pcfile(addr), ":", pcline(addr), "\n"); +} + +defn +notestk(addr) +{ + local pc, sp; + complex Ureg addr; + + pc = addr.pc\X; + sp = addr.sp\X; + + print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " "); + pfl(pc); + _stk({"PC", pc, "SP", sp, linkreg(addr)}, 1); +} + +defn +notelstk(addr) +{ + local pc, sp; + complex Ureg addr; + + pc = addr.pc\X; + sp = addr.sp\X; + + print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " "); + pfl(pc); + _stk({"PC", pc, "SP", sp, linkreg(addr)}, 1); +} + +defn params(param) +{ + while param do { + sym = head param; + print(sym[0], "=", itoa(sym[1], "%#ux")); + param = tail param; + if param then + print (","); + } +} + +stkprefix = ""; +stkignore = {}; +stkend = 0; + +defn locals(l) +{ + local sym; + + while l do { + sym = head l; + print(stkprefix, "\t", sym[0], "=", itoa(sym[1], "%#ux"), "\n"); + l = tail l; + } +} + +defn _stkign(frame) +{ + local file; + + file = pcfile(frame[0]); + s = stkignore; + while s do { + if regexp(head s, file) then + return 1; + s = tail s; + } + return 0; +} + +// print a stack trace +// +// in a run of leading frames in files matched by regexps in stkignore, +// only print the last one. +defn _stk(regs, dolocals) +{ + local stk, frame, pc, fn, done, callerpc, paramlist, locallist; + + stk = strace(regs); + if stkignore then { + while stk && tail stk && _stkign(head tail stk) do + stk = tail stk; + } + + callerpc = 0; + done = 0; + while stk && !done do { + frame = head stk; + stk = tail stk; + fn = frame[0]; + pc = frame[1]; + callerpc = frame[2]; + paramlist = frame[3]; + locallist = frame[4]; + + print(stkprefix, fmt(fn, 'a'), "("); + params(paramlist); + print(")"); + if pc != fn then + print("+", itoa(pc-fn, "%#ux")); + print(" "); + pfl(pc); + if dolocals then + locals(locallist); + if fn == var("threadmain") || fn == var("p9main") then + done=1; + if fn == var("threadstart") || fn == var("scheduler") then + done=1; + if callerpc == 0 then + done=1; + } + if callerpc && !done then { + print(stkprefix, fmt(callerpc, 'a'), " "); + pfl(callerpc); + } +} + +defn findsrc(file) +{ + local lst, src; + + if file[0] == '/' then { + src = file(file); + if src != {} then { + srcfiles = append srcfiles, file; + srctext = append srctext, src; + return src; + } + return {}; + } + + lst = srcpath; + while head lst do { + src = file(head lst+file); + if src != {} then { + srcfiles = append srcfiles, file; + srctext = append srctext, src; + return src; + } + lst = tail lst; + } +} + +defn line(addr) +{ + local src, file; + + file = pcfile(addr); + src = match(file, srcfiles); + + if src >= 0 then + src = srctext[src]; + else + src = findsrc(file); + + if src == {} then { + print("no source for ", file, "\n"); + return {}; + } + line = pcline(addr)-1; + print(file, ":", src[line], "\n"); +} + +defn addsrcdir(dir) +{ + dir = dir+"/"; + + if match(dir, srcpath) >= 0 then { + print("already in srcpath\n"); + return {}; + } + + srcpath = {dir}+srcpath; +} + +defn source() +{ + local l; + + l = srcpath; + while l do { + print(head l, "\n"); + l = tail l; + } + l = srcfiles; + + while l do { + print("\t", head l, "\n"); + l = tail l; + } +} + +defn Bsrc(addr) +{ + local lst; + + lst = srcpath; + file = pcfile(addr); + if file[0] == '/' && access(file) then { + rc("B "+file+":"+itoa(pcline(addr))); + return {}; + } + while head lst do { + name = head lst+file; + if access(name) then { + rc("B "+name+":"+itoa(pcline(addr))); + return {}; + } + lst = tail lst; + } + print("no source for ", file, "\n"); +} + +defn srcline(addr) +{ + local text, cline, line, file, src; + file = pcfile(addr); + src = match(file,srcfiles); + if (src>=0) then + src = srctext[src]; + else + src = findsrc(file); + if (src=={}) then + { + return "(no source)"; + } + return src[pcline(addr)-1]; +} + +defn src(addr) +{ + local src, file, line, cline, text; + + file = pcfile(addr); + src = match(file, srcfiles); + + if src >= 0 then + src = srctext[src]; + else + src = findsrc(file); + + if src == {} then { + print("no source for ", file, "\n"); + return {}; + } + + cline = pcline(addr)-1; + print(file, ":", cline+1, "\n"); + line = cline-5; + loop 0,10 do { + if line >= 0 then { + if line == cline then + print(">"); + else + print(" "); + text = src[line]; + if text == {} then + return {}; + print(line+1, "\t", text, "\n"); + } + line = line+1; + } +} + +defn step() // single step the process +{ + local lst, lpl, addr, bput; + + bput = 0; + if match(*PC, bplist) >= 0 then { // Sitting on a breakpoint + bput = fmt(*PC, bpfmt); + *bput = @bput; + } + + lst = follow(*PC); + + lpl = lst; + while lpl do { // place break points + *(head lpl) = bpinst; + lpl = tail lpl; + } + + startstop(pid); // do the step + + while lst do { // remove the breakpoints + addr = fmt(head lst, bpfmt); + *addr = @addr; + lst = tail lst; + } + if bput != 0 then + *bput = bpinst; +} + +defn bpset(addr) // set a breakpoint +{ + if status(pid) != "Stopped" then { + print("Waiting...\n"); + stop(pid); + } + if match(addr, bplist) >= 0 then + print("breakpoint already set at ", fmt(addr, 'a'), "\n"); + else { + *fmt(addr, bpfmt) = bpinst; + bplist = append bplist, addr; + } +} + +defn bptab() // print a table of breakpoints +{ + local lst, addr; + + lst = bplist; + while lst do { + addr = head lst; + print("\t", fmt(addr, 'X'), " ", fmt(addr, 'a'), " ", fmt(addr, 'i'), "\n"); + lst = tail lst; + } +} + +defn bpdel(addr) // delete a breakpoint +{ + local n, pc, nbplist; + + if addr == 0 then { + while bplist do { + pc = head bplist; + pc = fmt(pc, bpfmt); + *pc = @pc; + bplist = tail bplist; + } + return {}; + } + + n = match(addr, bplist); + if n < 0 then { + print("no breakpoint at ", fmt(addr, 'a'), "\n"); + return {}; + } + + addr = fmt(addr, bpfmt); + *addr = @addr; + + nbplist = {}; // delete from list + while bplist do { + pc = head bplist; + if pc != addr then + nbplist = append nbplist, pc; + bplist = tail bplist; + } + bplist = nbplist; // delete from memory +} + +defn cont() // continue execution +{ + local addr; + + addr = fmt(*PC, bpfmt); + if match(addr, bplist) >= 0 then { // Sitting on a breakpoint + *addr = @addr; + step(); // Step over + *addr = bpinst; + } + startstop(pid); // Run +} + +defn stopped(pid) // called from acid when a process changes state +{ + pfixstop(pid); + pstop(pid); // stub so this is easy to replace +} + +defn procs() // print status of processes +{ + local c, lst, cpid; + + cpid = pid; + lst = proclist; + while lst do { + np = head lst; + setproc(np); + if np == cpid then + c = '>'; + else + c = ' '; + print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n"); + lst = tail lst; + } + pid = cpid; + if pid != 0 then + setproc(pid); +} + +_asmlines = 30; + +defn asm(addr) +{ + local bound; + + bound = fnbound(addr); + + addr = fmt(addr, 'i'); + loop 1,_asmlines do { + print(fmt(addr, 'a'), " ", fmt(addr, 'X')); + print("\t", @addr++, "\n"); + if bound != {} && addr > bound[1] then { + lasmaddr = addr; + return {}; + } + } + lasmaddr = addr; +} + +defn casm() +{ + asm(lasmaddr); +} + +defn xasm(addr) +{ + local bound; + + bound = fnbound(addr); + + addr = fmt(addr, 'i'); + loop 1,_asmlines do { + print(fmt(addr, 'a'), " ", fmt(addr, 'X')); + print("\t", *addr++, "\n"); + if bound != {} && addr > bound[1] then { + lasmaddr = addr; + return {}; + } + } + lasmaddr = addr; +} + +defn xcasm() +{ + xasm(lasmaddr); +} + +defn win() +{ + local npid, estr; + + bplist = {}; + notes = {}; + + estr = "/sys/lib/acid/window '0 0 600 400' "+textfile; + if progargs != "" then + estr = estr+" "+progargs; + + npid = rc(estr); + npid = atoi(npid); + if npid == 0 then + error("win failed to create process"); + + setproc(npid); + stopped(npid); +} + +defn win2() +{ + local npid, estr; + + bplist = {}; + notes = {}; + + estr = "/sys/lib/acid/transcript '0 0 600 400' '100 100 700 500' "+textfile; + if progargs != "" then + estr = estr+" "+progargs; + + npid = rc(estr); + npid = atoi(npid); + if npid == 0 then + error("win failed to create process"); + + setproc(npid); + stopped(npid); +} + +printstopped = 1; +defn new() +{ + local a; + + bplist = {}; + newproc(progargs); + a = var("p9main"); + if a == {} then + a = var("main"); + if a == {} then + return {}; + bpset(a); + while *PC != a do + cont(); + bpdel(a); +} + +defn stmnt() // step one statement +{ + local line; + + line = pcline(*PC); + while 1 do { + step(); + if line != pcline(*PC) then { + src(*PC); + return {}; + } + } +} + +defn func() // step until we leave the current function +{ + local bound, end, start, pc; + + bound = fnbound(*PC); + if bound == {} then { + print("cannot locate text symbol\n"); + return {}; + } + + pc = *PC; + start = bound[0]; + end = bound[1]; + while pc >= start && pc < end do { + step(); + pc = *PC; + } +} + +defn next() +{ + local sp, bound, pc; + + sp = *SP; + bound = fnbound(*PC); + if bound == {} then { + print("cannot locate text symbol\n"); + return {}; + } + stmnt(); + pc = *PC; + if pc >= bound[0] && pc < bound[1] then + return {}; + + while (pc < bound[0] || pc > bound[1]) && sp >= *SP do { + step(); + pc = *PC; + } + src(*PC); +} + +defn maps() +{ + local m, mm; + + m = map(); + while m != {} do { + mm = head m; + m = tail m; + print(mm[2]\X, " ", mm[3]\X, " ", mm[4]\X, " ", mm[0], " ", mm[1], "\n"); + } +} + +defn dump(addr, n, fmt) +{ + loop 0, n do { + print(fmt(addr, 'X'), ": "); + addr = mem(addr, fmt); + } +} + +defn mem(addr, fmt) +{ + + local i, c, n; + + i = 0; + while fmt[i] != 0 do { + c = fmt[i]; + n = 0; + while '0' <= fmt[i] && fmt[i] <= '9' do { + n = 10*n + fmt[i]-'0'; + i = i+1; + } + if n <= 0 then n = 1; + addr = fmt(addr, fmt[i]); + while n > 0 do { + print(*addr++, " "); + n = n-1; + } + i = i+1; + } + print("\n"); + return addr; +} + +defn symbols(pattern) +{ + local l, s; + + l = symbols; + while l do { + s = head l; + if regexp(pattern, s[0]) then + print(s[0], "\t", s[1], "\t", s[2], "\t", s[3], "\n"); + l = tail l; + } +} + +defn havesymbol(name) +{ + local l, s; + + l = symbols; + while l do { + s = head l; + l = tail l; + if s[0] == name then + return 1; + } + return 0; +} + +defn spsrch(len) +{ + local addr, a, s, e; + + addr = *SP; + s = origin & 0x7fffffff; + e = etext & 0x7fffffff; + loop 1, len do { + a = *addr++; + c = a & 0x7fffffff; + if c > s && c < e then { + print("src(", a, ")\n"); + pfl(a); + } + } +} + +defn acidtypes() +{ + local syms; + local l; + + l = textfile(); + if l != {} then { + syms = "acidtypes"; + while l != {} do { + syms = syms + " " + ((head l)[0]); + l = tail l; + } + includepipe(syms); + } +} + +defn getregs() +{ + local regs, l; + + regs = {}; + l = registers; + while l != {} do { + regs = append regs, var(l[0]); + l = tail l; + } + return regs; +} + +defn setregs(regs) +{ + local l; + + l = registers; + while l != {} do { + var(l[0]) = regs[0]; + l = tail l; + regs = tail regs; + } + return regs; +} + +defn resetregs() +{ + local l; + + l = registers; + while l != {} do { + var(l[0]) = register(l[0]); + l = tail l; + } +} + +defn clearregs() +{ + local l; + + l = registers; + while l != {} do { + var(l[0]) = refconst(~0); + l = tail l; + } +} + +progargs=""; +print(acidfile); + +-- /usr/local/plan9/acid/386 +// 386 support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'b'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/386/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn linkreg(addr) +{ + return {}; +} + +defn stk() // trace +{ + _stk({"PC", *PC, "SP", *SP}, 0); +} + +defn lstk() // trace with locals +{ + _stk({"PC", *PC, "SP", *SP}, 1); +} + +defn gpr() // print general(hah hah!) purpose registers +{ + print("AX\t", *AX, " BX\t", *BX, " CX\t", *CX, " DX\t", *DX, "\n"); + print("DI\t", *DI, " SI\t", *SI, " BP\t", *BP, "\n"); +} + +defn spr() // print special processor registers +{ + local pc; + local cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + print("SP\t", *SP, " ECODE ", *ECODE, " EFLAG ", *EFLAGS, "\n"); + print("CS\t", *CS, " DS\t ", *DS, " SS\t", *SS, "\n"); + print("GS\t", *GS, " FS\t ", *FS, " ES\t", *ES, "\n"); + + cause = *TRAP; + print("TRAP\t", cause, " ", reason(cause), "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn mmregs() +{ + print("MM0\t", *MM0, " MM1\t", *MM1, "\n"); + print("MM2\t", *MM2, " MM3\t", *MM3, "\n"); + print("MM4\t", *MM4, " MM5\t", *MM5, "\n"); + print("MM6\t", *MM6, " MM7\t", *MM7, "\n"); +} + +defn pfixstop(pid) +{ + if *fmt(*PC-1, 'b') == 0xCC then { + // Linux stops us after the breakpoint, not at it + *PC = *PC-1; + } +} + + +defn pstop(pid) +{ + local l; + local pc; + local why; + + pc = *PC; + + // FIgure out why we stopped. + if *fmt(pc, 'b') == 0xCC then { + why = "breakpoint"; + + // fix up instruction for print; will put back later + *pc = @pc; + } else if *(pc-2\x) == 0x80CD then { + pc = pc-2; + why = "system call"; + } else + why = "stopped"; + + if printstopped then { + print(pid,": ", why, "\t"); + print(fmt(pc, 'a'), "\t", *fmt(pc, 'i'), "\n"); + } + + if why == "breakpoint" then + *fmt(pc, bpfmt) = bpinst; + + if printstopped && notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +aggr Ureg +{ + 'U' 0 di; + 'U' 4 si; + 'U' 8 bp; + 'U' 12 nsp; + 'U' 16 bx; + 'U' 20 dx; + 'U' 24 cx; + 'U' 28 ax; + 'U' 32 gs; + 'U' 36 fs; + 'U' 40 es; + 'U' 44 ds; + 'U' 48 trap; + 'U' 52 ecode; + 'U' 56 pc; + 'U' 60 cs; + 'U' 64 flags; + { + 'U' 68 usp; + 'U' 68 sp; + }; + 'U' 72 ss; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" di ", addr.di, "\n"); + print(" si ", addr.si, "\n"); + print(" bp ", addr.bp, "\n"); + print(" nsp ", addr.nsp, "\n"); + print(" bx ", addr.bx, "\n"); + print(" dx ", addr.dx, "\n"); + print(" cx ", addr.cx, "\n"); + print(" ax ", addr.ax, "\n"); + print(" gs ", addr.gs, "\n"); + print(" fs ", addr.fs, "\n"); + print(" es ", addr.es, "\n"); + print(" ds ", addr.ds, "\n"); + print(" trap ", addr.trap, "\n"); + print(" ecode ", addr.ecode, "\n"); + print(" pc ", addr.pc, "\n"); + print(" cs ", addr.cs, "\n"); + print(" flags ", addr.flags, "\n"); + print(" sp ", addr.sp, "\n"); + print(" ss ", addr.ss, "\n"); +}; +sizeofUreg = 76; + +aggr Linkdebug +{ + 'X' 0 version; + 'X' 4 map; +}; + +aggr Linkmap +{ + 'X' 0 addr; + 'X' 4 name; + 'X' 8 dynsect; + 'X' 12 next; + 'X' 16 prev; +}; + +defn +linkdebug() +{ + local a; + + if !havesymbol("_DYNAMIC") then + return 0; + + a = _DYNAMIC; + while *a != 0 do { + if *a == 21 then // 21 == DT_DEBUG + return *(a+4); + a = a+8; + } + return 0; +} + +defn +dynamicmap() +{ + if systype == "linux" || systype == "freebsd" then { + local r, m, n; + + r = linkdebug(); + if r then { + complex Linkdebug r; + m = r.map; + n = 0; + while m != 0 && n < 100 do { + complex Linkmap m; + if m.name && *(m.name\b) && access(*(m.name\s)) then + print("textfile({\"", *(m.name\s), "\", ", m.addr\X, "});\n"); + m = m.next; + n = n+1; + } + } + } +} + +defn +acidmap() +{ +// dynamicmap(); + acidtypes(); +} + +print(acidfile); |