devtrace.c 18 KB

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