devtrace.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. #include "netif.h"
  16. typedef struct Trace Trace;
  17. /* This is a trace--a segment of memory to watch for entries and exits */
  18. struct Trace {
  19. struct Trace *next;
  20. char *func;
  21. char *start;
  22. char *end;
  23. int enabled;
  24. char name[16];
  25. };
  26. enum {
  27. Qdir,
  28. Qctl,
  29. Qdata,
  30. };
  31. enum {
  32. TraceEntry = 1,
  33. TraceExit,
  34. };
  35. /* fix me make this programmable */
  36. enum {
  37. defaultlogsize = 8192,
  38. };
  39. /* This represents a trace "hit" or event */
  40. typedef struct Tracelog Tracelog;
  41. struct Tracelog {
  42. u64 ticks;
  43. int info;
  44. usize pc;
  45. /* these are different depending on type */
  46. usize dat[5];
  47. int machno;
  48. };
  49. //static Rendez tracesleep;
  50. static QLock traceslock;
  51. /* this will contain as many entries as there are valid pc values */
  52. static Trace **tracemap;
  53. static Trace *traces; /* This stores all the traces */
  54. //static Lock loglk;
  55. static Tracelog *tracelog = nil;
  56. int traceactive = 0;
  57. /* trace indices. These are just unsigned longs. You mask them
  58. * to get an index. This makes fifo empty/full etc. trivial.
  59. */
  60. static u32 pw = 0, pr = 0;
  61. static int tracesactive = 0;
  62. static int all = 0;
  63. static int watching = 0;
  64. static int slothits = 0;
  65. static unsigned int traceinhits = 0;
  66. static unsigned int newplfail = 0;
  67. static unsigned long logsize = defaultlogsize, logmask = defaultlogsize - 1;
  68. static int printsize = 0; //The length of a line being printed
  69. /* These are for observing a single process */
  70. static int *pidwatch = nil;
  71. static int numpids = 0;
  72. static const int PIDWATCHSIZE = 32; /* The number of PIDS that can be watched. Pretty arbitrary. */
  73. int codesize = 0;
  74. //static u64 lastestamp; /* last entry timestamp */
  75. //static u64 lastxstamp; /* last exit timestamp */
  76. /* Trace events can be either Entries or Exits */
  77. static char eventname[] = {
  78. [TraceEntry] = 'E',
  79. [TraceExit] = 'X',
  80. };
  81. static Dirtab tracedir[] = {
  82. {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0555},
  83. {"tracectl", {Qctl}, 0, 0664},
  84. {"trace", {Qdata}, 0, 0440},
  85. };
  86. char hex[] = {
  87. '0',
  88. '1',
  89. '2',
  90. '3',
  91. '4',
  92. '5',
  93. '6',
  94. '7',
  95. '8',
  96. '9',
  97. 'a',
  98. 'b',
  99. 'c',
  100. 'd',
  101. 'e',
  102. 'f',
  103. };
  104. /* big-endian ... */
  105. void
  106. hex8(u32 l, char *c)
  107. {
  108. int i;
  109. for(i = 2; i; i--){
  110. c[i - 1] = hex[l & 0xf];
  111. l >>= 4;
  112. }
  113. }
  114. void
  115. hex16(u32 l, char *c)
  116. {
  117. int i;
  118. for(i = 4; i; i--){
  119. c[i - 1] = hex[l & 0xf];
  120. l >>= 4;
  121. }
  122. }
  123. void
  124. hex32(u32 l, char *c)
  125. {
  126. int i;
  127. for(i = 8; i; i--){
  128. c[i - 1] = hex[l & 0xf];
  129. l >>= 4;
  130. }
  131. }
  132. void
  133. hex64(u64 l, char *c)
  134. {
  135. hex32(l >> 32, c);
  136. hex32(l, &c[8]);
  137. }
  138. static int
  139. lognonempty(void *v)
  140. {
  141. return pw - pr;
  142. }
  143. #if 0
  144. static int
  145. logfull(void)
  146. {
  147. return (pw - pr) >= logsize;
  148. }
  149. #endif
  150. static u64
  151. idx(u64 f)
  152. {
  153. return f & logmask;
  154. }
  155. /*
  156. * Check if the given trace overlaps any others
  157. * Returns 1 if there is overlap, 0 if clear.
  158. */
  159. int
  160. overlapping(Trace *p)
  161. {
  162. Trace *curr;
  163. curr = traces;
  164. if(!curr)
  165. return 0;
  166. do {
  167. if((curr->start < p->start && p->start < curr->end) ||
  168. (curr->start < p->end && p->end < curr->end))
  169. return 1;
  170. curr = curr->next;
  171. } while(curr != nil);
  172. return 0;
  173. }
  174. /* Make sure a PC is valid and traced; if so, return its Trace */
  175. /* if dopanic == 1, the kernel will panic on an invalid PC */
  176. struct Trace **
  177. traceslot(char *pc, int dopanic)
  178. {
  179. int index;
  180. struct Trace **p;
  181. if(pc > etext){
  182. if(dopanic)
  183. panic("Bad PC %p", pc);
  184. print("Invalid PC %p\n", pc);
  185. return nil;
  186. }
  187. index = (int)((usize)pc - KTZERO);
  188. if(index > codesize){
  189. if(dopanic){
  190. panic("Bad PC %p", pc);
  191. while(1)
  192. ;
  193. }
  194. print("Invalid PC %p\n", pc);
  195. return nil;
  196. }
  197. p = &tracemap[index];
  198. if(tracemap[index])
  199. ainc(&slothits);
  200. return p;
  201. }
  202. /* Check if the given PC is traced and return a Trace if so */
  203. struct Trace *
  204. traced(char *pc, int dopanic)
  205. {
  206. struct Trace **p;
  207. p = traceslot(pc, dopanic);
  208. if(p == nil)
  209. return nil;
  210. return *p;
  211. }
  212. /*
  213. * Return 1 if pid is being watched or no pids are being watched.
  214. * Return 0 if pids are being watched and the argument is not
  215. * among them.
  216. */
  217. int
  218. watchingpid(int pid)
  219. {
  220. int i;
  221. if(pidwatch[0] == 0)
  222. return 1;
  223. for(i = 0; i < numpids; i++){
  224. if(pidwatch[i] == pid)
  225. return 1;
  226. }
  227. return 0;
  228. }
  229. /*
  230. * Remove a trace.
  231. */
  232. void
  233. removetrace(Trace *p)
  234. {
  235. char *cp;
  236. struct Trace *prev;
  237. struct Trace *curr;
  238. struct Trace **slot;
  239. slot = traceslot(p->start, 0);
  240. for(cp = p->start; cp <= p->end; slot++, cp++)
  241. *slot = nil;
  242. curr = traces;
  243. if(curr == p){
  244. if(curr->next){
  245. traces = curr->next;
  246. } else {
  247. traces = nil; //this seems to work fine
  248. }
  249. free(curr);
  250. return;
  251. }
  252. prev = curr;
  253. curr = curr->next;
  254. do {
  255. if(curr == p){
  256. prev->next = curr->next;
  257. return;
  258. }
  259. prev = curr;
  260. curr = curr->next;
  261. } while(curr != nil);
  262. }
  263. /* it is recommended that you call these with something sane. */
  264. /* these next two functions assume you locked tracelock */
  265. /* Turn on a trace */
  266. void
  267. traceon(struct Trace *p)
  268. {
  269. char *cp;
  270. struct Trace **slot;
  271. slot = traceslot(p->start, 0);
  272. for(cp = p->start; cp <= p->end; slot++, cp++)
  273. *slot = p;
  274. p->enabled = 1;
  275. tracesactive++;
  276. }
  277. /* Turn off a trace */
  278. void
  279. traceoff(struct Trace *p)
  280. {
  281. char *cp;
  282. struct Trace **slot;
  283. slot = traceslot(p->start, 0);
  284. for(cp = p->start; cp <= p->end; slot++, cp++)
  285. *slot = nil;
  286. p->enabled = 0;
  287. tracesactive--;
  288. }
  289. /* Make a new tracelog (an event) */
  290. /* can return NULL, meaning, no record for you */
  291. static struct Tracelog *
  292. newpl(void)
  293. {
  294. u32 index;
  295. index = ainc((int *)&pw);
  296. return &tracelog[idx(index)];
  297. }
  298. /* Called every time a (traced) function starts */
  299. /* this is not really smp safe. FIX */
  300. void
  301. tracein(void *pc, usize a1, usize a2, usize a3, usize a4)
  302. {
  303. Proc *up = externup();
  304. struct Tracelog *pl;
  305. /* if we are here, tracing is active. Turn it off. */
  306. traceactive = 0;
  307. if(!traced(pc, 1)){
  308. traceactive = 1;
  309. return;
  310. }
  311. ainc((int *)&traceinhits);
  312. /* Continue if we are watching this pid or we're not watching any */
  313. if(!all)
  314. if(!up || !watchingpid(up->pid)){
  315. traceactive = 1;
  316. return;
  317. }
  318. pl = newpl();
  319. if(!pl){
  320. ainc((int *)&newplfail);
  321. traceactive = 1;
  322. return;
  323. }
  324. cycles(&pl->ticks);
  325. pl->pc = (usize)pc;
  326. if(up)
  327. pl->dat[0] = up->pid;
  328. else
  329. pl->dat[0] = (unsigned long)-1;
  330. pl->dat[1] = a1;
  331. pl->dat[2] = a2;
  332. pl->dat[3] = a3;
  333. pl->dat[4] = a4;
  334. pl->info = TraceEntry;
  335. pl->machno = machp()->machno;
  336. traceactive = 1;
  337. }
  338. /* Called every time a traced function exits */
  339. void
  340. traceout(void *pc, usize retval)
  341. {
  342. Proc *up = externup();
  343. struct Tracelog *pl;
  344. /* if we are here, tracing is active. Turn it off. */
  345. traceactive = 0;
  346. if(!traced(pc, 1)){
  347. traceactive = 1;
  348. return;
  349. }
  350. if(!all)
  351. if(!up || !watchingpid(up->pid)){
  352. traceactive = 1;
  353. return;
  354. }
  355. pl = newpl();
  356. if(!pl){
  357. traceactive = 1;
  358. return;
  359. }
  360. cycles(&pl->ticks);
  361. pl->pc = (usize)pc;
  362. if(up)
  363. pl->dat[0] = up->pid;
  364. else
  365. pl->dat[0] = (unsigned long)-1;
  366. pl->dat[1] = retval;
  367. pl->dat[2] = 0;
  368. pl->dat[3] = 0;
  369. pl->info = TraceExit;
  370. pl->machno = machp()->machno;
  371. traceactive = 1;
  372. }
  373. /* Create a new trace with the given range */
  374. static Trace *
  375. mktrace(void *func, void *start, void *end)
  376. {
  377. Trace *p;
  378. p = mallocz(sizeof p[0], 1);
  379. p->func = func;
  380. p->start = start;
  381. p->end = end;
  382. return p;
  383. }
  384. #if 0
  385. /* Get rid of an old trace */
  386. static void
  387. freetrace(Trace *p)
  388. {
  389. free(p);
  390. }
  391. #endif
  392. static Chan *
  393. traceattach(char *spec)
  394. {
  395. return devattach('T', spec);
  396. }
  397. static Walkqid *
  398. tracewalk(Chan *c, Chan *nc, char **name, int nname)
  399. {
  400. return devwalk(c, nc, name, nname, tracedir, nelem(tracedir), devgen);
  401. }
  402. static i32
  403. tracestat(Chan *c, u8 *db, i32 n)
  404. {
  405. return devstat(c, db, n, tracedir, nelem(tracedir), devgen);
  406. }
  407. static Chan *
  408. traceopen(Chan *c, int omode)
  409. {
  410. /* if there is no tracelog, allocate one. Open always fails
  411. * if the basic alloc fails. You can resize it later.
  412. */
  413. codesize = (usize)etext - (usize)KTZERO;
  414. if(!tracemap)
  415. //tracemap = mallocz(sizeof(struct tracemap *)*codesize, 1);
  416. tracemap = mallocz(sizeof(struct Trace *) * codesize, 1);
  417. if(!tracemap)
  418. error("tracemap malloc failed");
  419. if(!tracelog)
  420. tracelog = mallocz(sizeof(*tracelog) * logsize, 1);
  421. /* I guess malloc doesn't toss an error */
  422. if(!tracelog)
  423. error("tracelog malloc failed");
  424. if(!pidwatch)
  425. pidwatch = mallocz(sizeof(int) * PIDWATCHSIZE, 1);
  426. if(!pidwatch)
  427. error("pidwatch malloc failed");
  428. c = devopen(c, omode, tracedir, nelem(tracedir), devgen);
  429. return c;
  430. }
  431. static void
  432. traceclose(Chan *c)
  433. {
  434. }
  435. /*
  436. * Reading from the device, either the data or control files.
  437. * The data reading involves deep rminnich magic so we don't have
  438. * to call print(), which is traced.
  439. */
  440. static i32
  441. traceread(Chan *c, void *a, i32 n, i64 offset)
  442. {
  443. Proc *up = externup();
  444. char *buf;
  445. char *cp = a;
  446. struct Tracelog *pl;
  447. Trace *p;
  448. int i, j;
  449. int saveactive = traceactive;
  450. traceactive = 0;
  451. // static QLock gate;
  452. if(waserror()){
  453. traceactive = saveactive;
  454. nexterror();
  455. }
  456. if(c->qid.type == QTDIR){
  457. i32 l = devdirread(c, a, n, tracedir, nelem(tracedir), devgen);
  458. poperror();
  459. traceactive = saveactive;
  460. return l;
  461. }
  462. switch((int)c->qid.path){
  463. default:
  464. error("traceread: bad qid");
  465. case Qctl:
  466. i = 0;
  467. qlock(&traceslock);
  468. buf = malloc(READSTR);
  469. i += snprint(buf + i, READSTR - i, "logsize %lu\n", logsize);
  470. for(p = traces; p != nil; p = p->next)
  471. i += snprint(buf + i, READSTR - i, "trace %p %p new %s\n",
  472. p->start, p->end, p->name);
  473. for(p = traces; p != nil; p = p->next)
  474. i += snprint(buf + i, READSTR - i, "#trace %p traced? %p\n",
  475. p->func, traced(p->func, 0));
  476. for(p = traces; p != nil; p = p->next)
  477. if(p->enabled)
  478. i += snprint(buf + i, READSTR - i, "trace %s on\n",
  479. p->name);
  480. i += snprint(buf + i, READSTR - i, "#tracehits %d, in queue %d\n",
  481. pw, pw - pr);
  482. i += snprint(buf + i, READSTR - i, "#tracelog %p\n", tracelog);
  483. i += snprint(buf + i, READSTR - i, "#traceactive %d\n", saveactive);
  484. i += snprint(buf + i, READSTR - i, "#slothits %d\n", slothits);
  485. i += snprint(buf + i, READSTR - i, "#traceinhits %d\n", traceinhits);
  486. for(j = 0; j < numpids - 1; j++)
  487. i += snprint(buf + i, READSTR - i, "watch %d\n", pidwatch[j]);
  488. snprint(buf + i, READSTR - i, "watch %d\n", pidwatch[numpids - 1]);
  489. n = readstr(offset, a, n, buf);
  490. free(buf);
  491. qunlock(&traceslock);
  492. break;
  493. case Qdata:
  494. // Set the printsize
  495. /* 32-bit E PCPCPCPC TIMETIMETIMETIME PID# CR XXARG1XX XXARG2XX XXARG3XX XXARG4XX\n */
  496. if(sizeof(usize) == 4){
  497. printsize = 73; // 32-bit format
  498. } else {
  499. printsize = 121; // must be 64-bit
  500. }
  501. i = 0;
  502. while(lognonempty((void *)0)){
  503. int j;
  504. if((pw - pr) > logsize)
  505. pr = pw - logsize;
  506. pl = tracelog + idx(pr);
  507. if((i + printsize) > n)
  508. break;
  509. /* simple format */
  510. if(sizeof(usize) == 4){
  511. cp[0] = eventname[pl->info];
  512. cp++;
  513. *cp++ = ' ';
  514. hex32((u32)pl->pc, cp);
  515. cp[8] = ' ';
  516. cp += 9;
  517. hex64(pl->ticks, cp);
  518. cp[16] = ' ';
  519. cp += 17;
  520. hex16(pl->dat[0], cp);
  521. cp += 4;
  522. cp[0] = ' ';
  523. cp++;
  524. hex8(pl->machno, cp);
  525. cp += 2;
  526. cp[0] = ' ';
  527. cp++;
  528. for(j = 1; j < 4; j++){
  529. hex32(pl->dat[j], cp);
  530. cp[8] = ' ';
  531. cp += 9;
  532. }
  533. /* adjust for extra skip above */
  534. cp--;
  535. *cp++ = '\n';
  536. pr++;
  537. i += printsize;
  538. } else {
  539. cp[0] = eventname[pl->info];
  540. cp++;
  541. *cp++ = ' ';
  542. hex64((u64)pl->pc, cp);
  543. cp[16] = ' ';
  544. cp += 17;
  545. hex64(pl->ticks, cp);
  546. cp[16] = ' ';
  547. cp += 17;
  548. hex32(pl->dat[0], cp);
  549. cp += 8;
  550. cp[0] = ' ';
  551. cp++;
  552. cp[0] = ' ';
  553. cp++;
  554. cp[0] = ' ';
  555. cp++;
  556. cp[0] = ' ';
  557. cp++;
  558. hex8(pl->machno, cp);
  559. cp += 4;
  560. for(j = 1; j < 5; j++){
  561. hex64(pl->dat[j], cp);
  562. cp[16] = ' ';
  563. cp += 17;
  564. }
  565. cp--;
  566. *cp++ = '\n';
  567. pr++;
  568. i += printsize;
  569. }
  570. }
  571. n = i;
  572. break;
  573. }
  574. poperror();
  575. traceactive = saveactive;
  576. return n;
  577. }
  578. /*
  579. * Process commands sent to the ctl file.
  580. */
  581. static i32
  582. tracewrite(Chan *c, void *a, i32 n, i64 mm)
  583. {
  584. Proc *up = externup();
  585. char *tok[6]; //changed this so "tracein" works with the new 4th arg
  586. char *ep, *s = nil;
  587. Trace *p, **pp, *foo;
  588. int ntok;
  589. int saveactive = traceactive;
  590. traceactive = 0;
  591. qlock(&traceslock);
  592. if(waserror()){
  593. qunlock(&traceslock);
  594. if(s != nil)
  595. free(s);
  596. traceactive = saveactive;
  597. nexterror();
  598. }
  599. switch((usize)c->qid.path){
  600. default:
  601. error("tracewrite: bad qid");
  602. case Qctl:
  603. s = malloc(n + 1);
  604. memmove(s, a, n);
  605. s[n] = 0;
  606. ntok = tokenize(s, tok, nelem(tok));
  607. if(!strcmp(tok[0], "trace")) { /* 'trace' ktextaddr 'on'|'off'|'mk'|'del' [name] */
  608. if(ntok < 3){
  609. error("devtrace: usage: 'trace' [ktextaddr|name] 'on'|'off'|'mk'|'del' [name]");
  610. }
  611. for(pp = &traces; *pp != nil; pp = &(*pp)->next){
  612. if(!strcmp(tok[1], (*pp)->name))
  613. break;
  614. }
  615. p = *pp;
  616. if((ntok > 3) && (!strcmp(tok[3], "new"))){
  617. usize addr;
  618. char *start, *end, *func;
  619. if(ntok != 5){
  620. error("devtrace: usage: trace <ktextstart> <ktextend> new <name>");
  621. }
  622. addr = (usize)strtoul(tok[1], &ep, 16);
  623. if(addr < KTZERO)
  624. addr |= KTZERO;
  625. func = start = (void *)addr;
  626. if(*ep){
  627. error("devtrace: start address not in recognized format");
  628. }
  629. addr = (usize)strtoul(tok[2], &ep, 16);
  630. if(addr < KTZERO)
  631. addr |= KTZERO;
  632. end = (void *)addr;
  633. if(*ep){
  634. error("devtrace: end address not in recognized format");
  635. }
  636. if(start > end || start > etext || end > etext)
  637. error("devtrace: invalid address range");
  638. /* What do we do here? start and end are weird *
  639. if((addr < (usize)start) || (addr > (usize)end)
  640. error("devtrace: address out of bounds");
  641. */
  642. if(p){
  643. error("devtrace: trace already exists");
  644. }
  645. p = mktrace(func, start, end);
  646. for(foo = traces; foo != nil; foo = foo->next){
  647. if(!strcmp(tok[4], foo->name))
  648. error("devtrace: trace with that name already exists");
  649. }
  650. if(!overlapping(p)){
  651. p->next = traces;
  652. if(ntok < 5)
  653. snprint(p->name, sizeof p->name, "%p", func);
  654. else
  655. strncpy(p->name, tok[4], sizeof p->name);
  656. traces = p;
  657. } else {
  658. error("devtrace: given range overlaps with existing trace");
  659. }
  660. } else if(!strcmp(tok[2], "remove")){
  661. if(ntok != 3)
  662. error("devtrace: usage: trace <name> remove");
  663. if(p == nil){
  664. error("devtrace: trace not found");
  665. }
  666. removetrace(p);
  667. } else if(!strcmp(tok[2], "on")){
  668. if(ntok != 3)
  669. error("devtrace: usage: trace <name> on");
  670. if(p == nil){
  671. error("devtrace: trace not found");
  672. }
  673. if(!traced(p->func, 0)){
  674. traceon(p);
  675. }
  676. } else if(!strcmp(tok[2], "off")){
  677. if(ntok != 3)
  678. error("devtrace: usage: trace <name> off");
  679. if(p == nil){
  680. error("devtrace: trace not found");
  681. }
  682. if(traced(p->func, 0)){
  683. traceoff(p);
  684. }
  685. }
  686. } else if(!strcmp(tok[0], "query")){
  687. /* See if addr is being traced */
  688. Trace *p;
  689. usize addr;
  690. if(ntok != 2){
  691. error("devtrace: usage: query <addr>");
  692. }
  693. addr = (usize)strtoul(tok[1], &ep, 16);
  694. if(addr < KTZERO)
  695. addr |= KTZERO;
  696. p = traced((void *)addr, 0);
  697. if(p){
  698. print("Probing is enabled\n");
  699. } else {
  700. print("Probing is disabled\n");
  701. }
  702. } else if(!strcmp(tok[0], "size")){
  703. int l, size;
  704. struct Tracelog *newtracelog;
  705. if(ntok != 2)
  706. error("devtrace: usage: size <exponent>");
  707. l = strtoul(tok[1], &ep, 0);
  708. if(*ep){
  709. error("devtrace: size not in recognized format");
  710. }
  711. size = 1 << l;
  712. /* sort of foolish. Alloc new trace first, then free old. */
  713. /* and too bad if there are unread traces */
  714. newtracelog = mallocz(sizeof(*newtracelog) * size, 1);
  715. /* does malloc throw waserror? I don't know */
  716. if(newtracelog){
  717. free(tracelog);
  718. tracelog = newtracelog;
  719. logsize = size;
  720. logmask = size - 1;
  721. pr = pw = 0;
  722. } else {
  723. error("devtrace: can't allocate that much");
  724. }
  725. } else if(!strcmp(tok[0], "testtracein")){
  726. /* Manually jump to a certain bit of traced code */
  727. usize pc, a1, a2, a3, a4;
  728. int x;
  729. if(ntok != 6)
  730. error("devtrace: usage: testtracein <pc> <arg1> <arg2> <arg3> <arg4>");
  731. pc = (usize)strtoul(tok[1], &ep, 16);
  732. if(pc < KTZERO)
  733. pc |= KTZERO;
  734. a1 = (usize)strtoul(tok[2], &ep, 16);
  735. a2 = (usize)strtoul(tok[3], &ep, 16);
  736. a3 = (usize)strtoul(tok[4], &ep, 16);
  737. a4 = (usize)strtoul(tok[5], &ep, 16);
  738. if(traced((void *)pc, 0)){
  739. x = splhi();
  740. watching = 1;
  741. tracein((void *)pc, a1, a2, a3, a4);
  742. watching = 0;
  743. splx(x);
  744. }
  745. } else if(!strcmp(tok[0], "watch")){
  746. /* Watch a certain PID */
  747. int pid;
  748. if(ntok != 2){
  749. error("devtrace: usage: watch [0|<PID>]");
  750. }
  751. pid = atoi(tok[1]);
  752. if(pid == 0){
  753. pidwatch = mallocz(sizeof(int) * PIDWATCHSIZE, 1);
  754. numpids = 0;
  755. } else if(pid < 0){
  756. error("PID must be greater than zero.");
  757. } else if(numpids < PIDWATCHSIZE){
  758. pidwatch[numpids] = pid;
  759. ainc(&numpids);
  760. } else {
  761. error("pidwatch array full!");
  762. }
  763. } else if(!strcmp(tok[0], "start")){
  764. if(ntok != 1)
  765. error("devtrace: usage: start");
  766. saveactive = 1;
  767. } else if(!strcmp(tok[0], "stop")){
  768. if(ntok != 1)
  769. error("devtrace: usage: stop");
  770. saveactive = 0;
  771. all = 0;
  772. } else if(!strcmp(tok[0], "all")){
  773. if(ntok != 1)
  774. error("devtrace: usage: all");
  775. saveactive = 1;
  776. all = 1;
  777. } else {
  778. error("devtrace: usage: 'trace' [ktextaddr|name] 'on'|'off'|'mk'|'del' [name] or: 'size' buffersize (power of 2)");
  779. }
  780. free(s);
  781. break;
  782. }
  783. poperror();
  784. qunlock(&traceslock);
  785. traceactive = saveactive;
  786. return n;
  787. }
  788. Dev tracedevtab = {
  789. .dc = 'T',
  790. .name = "trace",
  791. .reset = devreset,
  792. .init = devinit,
  793. .shutdown = devshutdown,
  794. .attach = traceattach,
  795. .walk = tracewalk,
  796. .stat = tracestat,
  797. .open = traceopen,
  798. .create = devcreate,
  799. .close = traceclose,
  800. .read = traceread,
  801. .bread = devbread,
  802. .write = tracewrite,
  803. .bwrite = devbwrite,
  804. .remove = devremove,
  805. .wstat = devwstat,
  806. };