summaryrefslogtreecommitdiff
path: root/web/l19.txt
diff options
context:
space:
mode:
Diffstat (limited to 'web/l19.txt')
-rw-r--r--web/l19.txt1412
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);