]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/acid/port
acid: watchpoint support
[plan9front.git] / sys / lib / acid / port
1 // portable acid for all architectures
2
3 defn pfl(addr)
4 {
5         print(pcfile(addr), ":", pcline(addr), "\n");
6 }
7
8 defn
9 notestk(addr)
10 {
11         local pc, sp;
12         complex Ureg addr;
13
14         pc = addr.pc\A;
15         sp = addr.sp\A;
16
17         print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " ");
18         pfl(pc);
19         _stk(pc, sp, linkreg(addr), 1);
20 }
21
22 defn
23 notelstk(addr)
24 {
25         local pc, sp;
26         complex Ureg addr;
27
28         pc = addr.pc\A;
29         sp = addr.sp\A;
30
31         print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " ");
32         pfl(pc);
33         _stk(pc, sp, linkreg(addr), 1);
34 }
35
36 defn params(param)
37 {
38         while param do {
39                 sym = head param;
40                 print(sym[0], "=", itoa(sym[1], "%ux"));
41                 param = tail param;
42                 if param then
43                         print (",");
44         }       
45 }
46
47 stkprefix = "";
48 stkignore = {};
49 stkend = 0;
50
51 defn locals(l)
52 {
53         local sym;
54
55         while l do {
56                 sym = head l;
57                 print(stkprefix, "\t", sym[0], "=", itoa(sym[1], "%ux"), "\n");
58                 l = tail l;
59         }       
60 }
61
62 defn _stkign(file)
63 {
64         s = stkignore;
65         while s do {
66                 if regexp(head s, file) then
67                         return 1;
68                 s = tail s;
69         }
70         return 0;
71 }
72
73 // print a stack trace
74 //
75 // in a run of leading frames in files matched by regexps in stkignore,
76 // only print the last one.
77 defn _stk(pc, sp, link, dolocals)
78 {
79         local stk, ign, last, lastpc;
80
81         stk = strace(pc, sp, link);
82         if stkignore then
83                 ign = 1;
84         else
85                 ign = 0;
86         last = stk;
87         lastpc = pc;
88         while stk do {
89                 if ign then {
90                         if !_stkign(pcfile(pc)) then {
91                                 ign = 0;
92                                 stk = last;
93                                 pc = lastpc;
94                         }
95                 }
96                 frame = head stk;
97                 if !ign then {
98                         print(stkprefix, fmt(frame[0], 'a'), "(");
99                         params(frame[2]);
100                         print(")+", itoa(pc-frame[0], "%ux"), " ");
101                         pfl(pc);
102                         if dolocals then
103                                 locals(frame[3]);
104                 }
105                 last = stk;
106                 lastpc = pc;
107                 stk = tail stk;
108                 pc = frame[1];
109         }
110         print(stkprefix, fmt(pc, 'a'), " ");
111         pfl(pc);
112 }
113
114 defn findsrc(file)
115 {
116         local lst, src;
117
118         if file[0] == '/' then {
119                 src = file(file);
120                 if src != {} then {
121                         srcfiles = append srcfiles, file;
122                         srctext = append srctext, src;
123                         return src;
124                 }
125                 return {};
126         }
127
128         lst = srcpath;
129         while head lst do {
130                 src = file(head lst+file);
131                 if src != {} then {
132                         srcfiles = append srcfiles, file;
133                         srctext = append srctext, src;
134                         return src;
135                 }
136                 lst = tail lst;
137         }
138 }
139
140 defn line(addr)
141 {
142         local src, file;
143
144         file = pcfile(addr);
145         src = match(file, srcfiles);
146
147         if src >= 0 then
148                 src = srctext[src];
149         else
150                 src = findsrc(file);
151
152         if src == {} then {
153                 print("no source for ", file, "\n");
154                 return {};
155         }
156         line = pcline(addr)-1;
157         print(file, ":", line+1, ":", src[line], "\n");
158 }
159
160 defn addsrcdir(dir)
161 {
162         dir = dir+"/";
163
164         if match(dir, srcpath) >= 0 then {
165                 print("already in srcpath\n");
166                 return {};
167         }
168
169         srcpath = {dir}+srcpath;
170 }
171
172 defn source()
173 {
174         local l;
175
176         l = srcpath;
177         while l do {
178                 print(head l, "\n");
179                 l = tail l;
180         }
181         l = srcfiles;
182
183         while l do {
184                 print("\t", head l, "\n");
185                 l = tail l;
186         }
187 }
188
189 defn Bsrc(addr)
190 {
191         local lst;
192
193         lst = srcpath;
194         file = pcfile(addr);
195         if file[0] == '/' && access(file) then {
196                 rc("B "+file+":"+itoa(pcline(addr)));
197                 return {};
198         }
199         while head lst do {
200                 name = head lst+file;
201                 if access(name) then {
202                         rc("B "+name+":"+itoa(pcline(addr)));
203                         return {};
204                 }
205                 lst = tail lst;
206         }
207         print("no source for ", file, "\n");
208 }
209
210 defn srcline(addr)
211 {
212         local text, cline, line, file, src;
213         file = pcfile(addr);
214         src = match(file,srcfiles);
215         if (src>=0) then
216                 src = srctext[src];
217         else
218                 src = findsrc(file);
219         if (src=={}) then
220         {
221                 return "(no source)";
222         }
223         return src[pcline(addr)-1];
224 }
225
226 defn src(addr)
227 {
228         local src, file, line, cline, text;
229
230         file = pcfile(addr);
231         src = match(file, srcfiles);
232
233         if src >= 0 then
234                 src = srctext[src];
235         else
236                 src = findsrc(file);
237
238         if src == {} then {
239                 print("no source for ", file, "\n");
240                 return {};
241         }
242
243         cline = pcline(addr)-1;
244         print(file, ":", cline+1, "\n");
245         line = cline-5;
246         loop 0,10 do {
247                 if line >= 0 then {
248                         text = src[line];
249                         if text == {} then
250                                 return {};
251                         if line == cline then
252                                 print(">");
253                         else
254                                 print(" ");
255                         print(line+1, "\t", text, "\n");
256                 }
257                 line = line+1;
258         }       
259 }
260
261 defn step()                                     // single step the process
262 {
263         local lst, lpl, addr, bput;
264
265         bput = 0;
266         if match(*PC, bplist) >= 0 then {       // Sitting on a breakpoint
267                 bput = fmt(*PC, bpfmt);
268                 *bput = @bput;
269         }
270         wpupdate(0);
271
272         lst = follow(*PC);
273
274         lpl = lst;
275         while lpl do {                          // place break points
276                 *(head lpl) = bpinst;
277                 lpl = tail lpl;
278         }
279
280         startstop(pid);                         // do the step
281
282         while lst do {                          // remove the breakpoints
283                 addr = fmt(head lst, bpfmt);
284                 *addr = @addr;
285                 lst = tail lst;
286         }
287         if bput != 0 then
288                 *bput = bpinst;
289 }
290
291 defn bpset(addr)                                // set a breakpoint
292 {
293         if status(pid) != "Stopped" then {
294                 print("Waiting...\n");
295                 stop(pid);
296         }
297         if match(addr, bplist) >= 0 then
298                 print("breakpoint already set at ", fmt(addr, 'a'), "\n");
299         else {
300                 *fmt(addr, bpfmt) = bpinst;
301                 bplist = append bplist, addr;
302         }
303 }
304
305 defn bptab()                                    // print a table of breakpoints
306 {
307         local lst, addr;
308
309         lst = bplist;
310         while lst do {
311                 addr = head lst;
312                 print("\t", fmt(addr, 'A'), " ", fmt(addr, 'a'), "  ", fmt(addr, 'i'), "\n");
313                 lst = tail lst;
314         }
315 }
316
317 defn bpdel(addr)                                // delete a breakpoint
318 {
319         local n, pc, nbplist;
320
321         n = match(addr, bplist);
322         if n < 0  then {
323                 print("no breakpoint at ", fmt(addr, 'a'), "\n");
324                 return {};
325         }
326
327         addr = fmt(addr, bpfmt);
328         *addr = @addr;
329
330         nbplist = {};                           // delete from list
331         while bplist do {
332                 pc = head bplist;
333                 if pc != addr then
334                         nbplist = append nbplist, pc;
335                 bplist = tail bplist;
336         }
337         bplist = nbplist;                       // delete from memory
338 }
339
340 defn wpflush()                                  // copy wplist to /proc/$pid/watchpt
341 {
342         local s, lst, el;
343
344         lst = wplist;
345         s = "";
346         while lst do {
347                 el = head lst;
348                 s = s + (el[0] + " " + itoa(el[1]) + " " + itoa(el[2]) + "\n");
349                 lst = tail lst;
350         }
351         lst = proclist;
352         while lst do {
353                 if access("/proc/"+itoa(head lst)+"/watchpt") then
354                         printto("/proc/"+itoa(head lst)+"/watchpt", s);
355                 lst = tail lst;
356         }
357 }
358
359 defn wpset(type, addr, len)                     // set a watchpoint
360 {
361         local lst;
362
363         if status(pid) != "Stopped" then {
364                 print("Waiting...\n");
365                 stop(pid);
366         }
367         if !regexp("^[rwx\\-]+$", type) then {
368                 print("invalid type\n");
369                 return {};
370         }
371         lst = proclist;
372         while lst do {
373                 if rc("echo '"+type+" "+itoa(addr)+" "+itoa(len)+"' >> /proc/"+itoa(head lst)+"/watchpt") != "" then
374                         return {};
375                 lst = tail lst;
376         }
377         wplist = append wplist, {type, addr, len, {}};
378 }
379
380 defn wptab()                                    // print a table of watchpoints
381 {
382         local lst, el;
383
384         lst = wplist;
385         while lst do {
386                 el = head lst;
387                 print("\t", el[0], " ", fmt(el[1], 'A'), " ", fmt(el[1], 'a'), " ", fmt(el[2], 'd'), "\n");
388                 lst = tail lst;
389         }
390 }
391
392 defn wpdel(addr)
393 {
394         local lst, el, found, nwplist;
395         
396         lst = wplist;
397         found = 0;
398         nwplist = {};
399         while lst do {
400                 el = head lst;
401                 if el[1] == addr then
402                         found = 1;
403                 else
404                         nwplist = append nwplist, el;
405                 lst = tail lst;
406         }
407         if found == 0 then {
408                 print("no watchpoint at ", fmt(addr, 'a'), "\n");
409                 return {};
410         }
411         wplist = nwplist;
412         wpflush();
413 }
414
415 defn bytes(b)
416 {
417         local s;
418         
419         s = "";
420         while b do {
421                 s = s + itoa(head b, "%#.2x ");
422                 b = tail b;
423         }
424         return s;
425 }
426
427 defn wpupdate(ch)                               // update remembered values
428 {
429         local el, nwplist, mem, lst, i;
430         
431         lst = wplist;
432         nwplist = {};
433         while lst do {
434                 el = head lst;
435                 i = 0;
436                 mem = {};
437                 while i < el[2] do {
438                         mem = append mem, *((el[1] + i)\b);
439                         i = i + 1;
440                 }
441                 if ch && el[3] != {} && el[3] != mem then {
442                         print("\t", fmt(el[1], 'a'), "\twas ", bytes(el[3]), "\n");
443                         print("\t", fmt(el[1], 'a'), "\tis  ", bytes(mem), "\n");
444                 }
445                 nwplist = append nwplist, {el[0], el[1], el[2], mem};
446                 lst = tail lst;
447         }
448         wplist = nwplist;
449 }
450
451 defn wpprocess()                                // trapped at watchpoint
452 {
453         local pts;
454         local el;
455         
456         pts = getfields(getfields(notes[0], " ", 1)[2], ",", 1);
457         while pts do {
458                 el = head pts;
459                 el = wplist[atoi(el)];
460                 if el != {} then {
461                         print("\ttriggered ", el[0], " watchpoint at ", fmt(el[1], 'a'), " (", fmt(el[1], 'A'), ")\n");
462                 }
463                 pts = tail pts;
464         }
465         wpupdate(1);
466 }
467
468 defn cont()                                     // continue execution
469 {
470         local addr;
471
472         addr = fmt(*PC, bpfmt);
473         if match(addr, bplist) >= 0 then {      // Sitting on a breakpoint
474                 *addr = @addr;
475                 step();                         // Step over
476                 *addr = bpinst;
477         }
478         wpupdate(0);
479         startstop(pid);                         // Run
480 }
481
482 defn stopped(pid)               // called from acid when a process changes state
483 {
484         pstop(pid);             // stub so this is easy to replace
485 }
486
487 defn procs()                    // print status of processes
488 {
489         local c, lst, cpid;
490
491         cpid = pid;
492         lst = proclist;
493         while lst do {
494                 np = head lst;
495                 setproc(np);
496                 if np == cpid then
497                         c = '>';
498                 else
499                         c = ' ';
500                 print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n");
501                 lst = tail lst;
502         }
503         pid = cpid;
504         if pid != 0 then
505                 setproc(pid);
506 }
507
508 _asmlines = 30;
509
510 defn asm(addr)
511 {
512         local bound;
513
514         bound = fnbound(addr);
515
516         addr = fmt(addr, 'i');
517         loop 1,_asmlines do {
518                 print(fmt(addr, 'a'), " ", fmt(addr, 'A'));
519                 print("\t", @addr++, "\n");
520                 if bound != {} && addr > bound[1] then {
521                         lasmaddr = addr;
522                         return {};
523                 }
524         }
525         lasmaddr = addr;
526 }
527
528 defn casm()
529 {
530         asm(lasmaddr);
531 }
532
533 defn win()
534 {
535         local npid, estr;
536
537         bplist = {};
538         wplist = {};
539         notes = {};
540
541         estr = "/sys/lib/acid/window '0 0 600 400' "+textfile;
542         if progargs != "" then
543                 estr = estr+" "+progargs;
544
545         npid = rc(estr);
546         npid = atoi(npid);
547         if npid == 0 then
548                 error("win failed to create process");
549
550         setproc(npid);
551         stopped(npid);
552 }
553
554 defn win2()
555 {
556         local npid, estr;
557
558         bplist = {};
559         wplist = {};
560         notes = {};
561
562         estr = "/sys/lib/acid/transcript '0 0 600 400' '100 100 700 500' "+textfile;
563         if progargs != "" then
564                 estr = estr+" "+progargs;
565
566         npid = rc(estr);
567         npid = atoi(npid);
568         if npid == 0 then
569                 error("win failed to create process");
570
571         setproc(npid);
572         stopped(npid);
573 }
574
575 defn new()
576 {
577         bplist = {};
578         wplist = {};
579         newproc(progargs);
580         // Dont miss the delay slot calls
581         bpset(follow(main)[0]);
582         cont();
583         bpdel(*PC);
584 }
585
586 defn stmnt()                    // step one statement
587 {
588         local line;
589
590         line = pcline(*PC);
591         while 1 do {
592                 step();
593                 if line != pcline(*PC) then {
594                         src(*PC);
595                         return {};
596                 }
597         }
598 }
599
600 defn func()                     // step until we leave the current function
601 {
602         local bound, end, start, pc;
603
604         bound = fnbound(*PC);
605         if bound == {} then {
606                 print("cannot locate text symbol\n");
607                 return {};
608         }
609
610         pc = *PC;
611         start = bound[0];
612         end = bound[1];
613         while pc >= start && pc < end do {
614                 step();
615                 pc = *PC;
616         }
617 }
618
619 defn next()
620 {
621         local sp, bound;
622
623         sp = *SP;
624         bound = fnbound(*PC);
625         stmnt();
626         pc = *PC;
627         if pc >= bound[0] && pc < bound[1] then
628                 return {};
629
630         while (pc < bound[0] || pc > bound[1]) && sp >= *SP do {
631                 step();
632                 pc = *PC;
633         }
634         src(*PC);
635 }
636
637 defn dump(addr, n, fmt)
638 {
639         // see definition of dump in acid manual: it does n+1 iterations
640         loop 0, n do {
641                 print(fmt(addr, 'A'), ": ");
642                 addr = mem(addr, fmt);
643         }
644 }
645
646 defn mem(addr, fmt)
647 {
648
649         local i, c, n;
650
651         i = 0;
652         while fmt[i] != 0 do {
653                 c = fmt[i];
654                 n = 0;
655                 while '0' <= fmt[i] && fmt[i] <= '9' do {
656                         n = 10*n + fmt[i]-'0';
657                         i = i+1;
658                 }
659                 if n <= 0 then n = 1;
660                 addr = fmt(addr, fmt[i]);
661                 while n > 0 do {
662                         print(*addr++, " ");
663                         n = n-1;
664                 }
665                 i = i+1;
666         }
667         print("\n");
668         return addr;
669 }
670
671 defn symbols(pattern)
672 {
673         local l, s;
674
675         l = symbols;
676         while l do {
677                 s = head l;
678                 if regexp(pattern, s[0]) then
679                         print(s[0], "\t", s[1], "\t", s[2], "\n");
680                 l = tail l;
681         }
682 }
683
684 defn spsrch(len)
685 {
686         local addr, a, s, e;
687
688         addr = *SP;
689         s = origin & 0x7fffffff;
690         e = etext & 0x7fffffff;
691         loop 1, len do {
692                 a = *addr++;
693                 c = a & 0x7fffffff;
694                 if c > s && c < e then {
695                         print("src(", a, ")\n");
696                         pfl(a);
697                 }                       
698         }
699 }
700
701 defn procattach()
702 {
703         wpflush();
704 }
705
706 defn dying()
707 {
708         wplist = {};
709         wpflush();
710         derp();
711 }
712
713 progargs="";
714 print("/sys/lib/acid/port");