xv6-65oo2/web/l19.txt
2008-09-03 04:50:04 +00:00

1413 lines
22 KiB
Plaintext

-- 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);