tracetool 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #!/bin/sh
  2. #
  3. # Code generator for trace events
  4. #
  5. # Copyright IBM, Corp. 2010
  6. #
  7. # This work is licensed under the terms of the GNU GPL, version 2. See
  8. # the COPYING file in the top-level directory.
  9. # Disable pathname expansion, makes processing text with '*' characters simpler
  10. set -f
  11. usage()
  12. {
  13. cat >&2 <<EOF
  14. usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
  15. Generate tracing code for a file on stdin.
  16. Backends:
  17. --nop Tracing disabled
  18. --simple Simple built-in backend
  19. --stderr Stderr built-in backend
  20. --ust LTTng User Space Tracing backend
  21. --dtrace DTrace/SystemTAP backend
  22. Output formats:
  23. -h Generate .h file
  24. -c Generate .c file
  25. -d Generate .d file (DTrace only)
  26. --stap Generate .stp file (DTrace with SystemTAP only)
  27. Options:
  28. --binary [path] Full path to QEMU binary
  29. --target-arch [arch] QEMU emulator target arch
  30. --target-type [type] QEMU emulator target type ('system' or 'user')
  31. --probe-prefix [prefix] Prefix for dtrace probe names
  32. (default: qemu-\$targettype-\$targetarch)
  33. EOF
  34. exit 1
  35. }
  36. # Print a line without interpreting backslash escapes
  37. #
  38. # The built-in echo command may interpret backslash escapes without an option
  39. # to disable this behavior.
  40. puts()
  41. {
  42. printf "%s\n" "$1"
  43. }
  44. # Get the name of a trace event
  45. get_name()
  46. {
  47. local name
  48. name=${1%%\(*}
  49. echo "${name##* }"
  50. }
  51. # Get the given property of a trace event
  52. # 1: trace-events line
  53. # 2: property name
  54. # -> return 0 if property is present, or 1 otherwise
  55. has_property()
  56. {
  57. local props prop
  58. props=${1%%\(*}
  59. props=${props% *}
  60. for prop in $props; do
  61. if [ "$prop" = "$2" ]; then
  62. return 0
  63. fi
  64. done
  65. return 1
  66. }
  67. # Get the argument list of a trace event, including types and names
  68. get_args()
  69. {
  70. local args
  71. args=${1#*\(}
  72. args=${args%%\)*}
  73. echo "$args"
  74. }
  75. # Get the argument name list of a trace event
  76. get_argnames()
  77. {
  78. local nfields field name sep
  79. nfields=0
  80. sep="$2"
  81. for field in $(get_args "$1"); do
  82. nfields=$((nfields + 1))
  83. # Drop pointer star
  84. field=${field#\*}
  85. # Only argument names have commas at the end
  86. name=${field%,}
  87. test "$field" = "$name" && continue
  88. printf "%s%s " $name $sep
  89. done
  90. # Last argument name
  91. if [ "$nfields" -gt 1 ]
  92. then
  93. printf "%s" "$name"
  94. fi
  95. }
  96. # Get the number of arguments to a trace event
  97. get_argc()
  98. {
  99. local name argc
  100. argc=0
  101. for name in $(get_argnames "$1", ","); do
  102. argc=$((argc + 1))
  103. done
  104. echo $argc
  105. }
  106. # Get the format string including double quotes for a trace event
  107. get_fmt()
  108. {
  109. puts "${1#*)}"
  110. }
  111. linetoh_begin_nop()
  112. {
  113. return
  114. }
  115. linetoh_nop()
  116. {
  117. local name args
  118. name=$(get_name "$1")
  119. args=$(get_args "$1")
  120. # Define an empty function for the trace event
  121. cat <<EOF
  122. static inline void trace_$name($args)
  123. {
  124. }
  125. EOF
  126. }
  127. linetoh_end_nop()
  128. {
  129. return
  130. }
  131. linetoc_begin_nop()
  132. {
  133. return
  134. }
  135. linetoc_nop()
  136. {
  137. # No need for function definitions in nop backend
  138. return
  139. }
  140. linetoc_end_nop()
  141. {
  142. return
  143. }
  144. linetoh_begin_simple()
  145. {
  146. cat <<EOF
  147. #include "trace/simple.h"
  148. EOF
  149. simple_event_num=0
  150. }
  151. cast_args_to_uint64_t()
  152. {
  153. local arg
  154. for arg in $(get_argnames "$1", ","); do
  155. printf "%s" "(uint64_t)(uintptr_t)$arg"
  156. done
  157. }
  158. linetoh_simple()
  159. {
  160. local name args argc trace_args
  161. name=$(get_name "$1")
  162. args=$(get_args "$1")
  163. argc=$(get_argc "$1")
  164. trace_args="$simple_event_num"
  165. if [ "$argc" -gt 0 ]
  166. then
  167. trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
  168. fi
  169. cat <<EOF
  170. static inline void trace_$name($args)
  171. {
  172. trace$argc($trace_args);
  173. }
  174. EOF
  175. simple_event_num=$((simple_event_num + 1))
  176. }
  177. linetoh_end_simple()
  178. {
  179. cat <<EOF
  180. #define NR_TRACE_EVENTS $simple_event_num
  181. extern TraceEvent trace_list[NR_TRACE_EVENTS];
  182. EOF
  183. }
  184. linetoc_begin_simple()
  185. {
  186. cat <<EOF
  187. #include "trace.h"
  188. TraceEvent trace_list[] = {
  189. EOF
  190. simple_event_num=0
  191. }
  192. linetoc_simple()
  193. {
  194. local name
  195. name=$(get_name "$1")
  196. cat <<EOF
  197. {.tp_name = "$name", .state=0},
  198. EOF
  199. simple_event_num=$((simple_event_num + 1))
  200. }
  201. linetoc_end_simple()
  202. {
  203. cat <<EOF
  204. };
  205. EOF
  206. }
  207. #STDERR
  208. linetoh_begin_stderr()
  209. {
  210. cat <<EOF
  211. #include <stdio.h>
  212. #include "trace/stderr.h"
  213. extern TraceEvent trace_list[];
  214. EOF
  215. stderr_event_num=0
  216. }
  217. linetoh_stderr()
  218. {
  219. local name args argnames argc fmt
  220. name=$(get_name "$1")
  221. args=$(get_args "$1")
  222. argnames=$(get_argnames "$1" ",")
  223. argc=$(get_argc "$1")
  224. fmt=$(get_fmt "$1")
  225. if [ "$argc" -gt 0 ]; then
  226. argnames=", $argnames"
  227. fi
  228. cat <<EOF
  229. static inline void trace_$name($args)
  230. {
  231. if (trace_list[$stderr_event_num].state != 0) {
  232. fprintf(stderr, "$name " $fmt "\n" $argnames);
  233. }
  234. }
  235. EOF
  236. stderr_event_num=$((stderr_event_num + 1))
  237. }
  238. linetoh_end_stderr()
  239. {
  240. cat <<EOF
  241. #define NR_TRACE_EVENTS $stderr_event_num
  242. EOF
  243. }
  244. linetoc_begin_stderr()
  245. {
  246. cat <<EOF
  247. #include "trace.h"
  248. TraceEvent trace_list[] = {
  249. EOF
  250. stderr_event_num=0
  251. }
  252. linetoc_stderr()
  253. {
  254. local name
  255. name=$(get_name "$1")
  256. cat <<EOF
  257. {.tp_name = "$name", .state=0},
  258. EOF
  259. stderr_event_num=$(($stderr_event_num + 1))
  260. }
  261. linetoc_end_stderr()
  262. {
  263. cat <<EOF
  264. };
  265. EOF
  266. }
  267. #END OF STDERR
  268. # Clean up after UST headers which pollute the namespace
  269. ust_clean_namespace() {
  270. cat <<EOF
  271. #undef mutex_lock
  272. #undef mutex_unlock
  273. #undef inline
  274. #undef wmb
  275. EOF
  276. }
  277. linetoh_begin_ust()
  278. {
  279. echo "#include <ust/tracepoint.h>"
  280. ust_clean_namespace
  281. }
  282. linetoh_ust()
  283. {
  284. local name args argnames
  285. name=$(get_name "$1")
  286. args=$(get_args "$1")
  287. argnames=$(get_argnames "$1", ",")
  288. cat <<EOF
  289. DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
  290. #define trace_$name trace_ust_$name
  291. EOF
  292. }
  293. linetoh_end_ust()
  294. {
  295. return
  296. }
  297. linetoc_begin_ust()
  298. {
  299. cat <<EOF
  300. #include <ust/marker.h>
  301. $(ust_clean_namespace)
  302. #include "trace.h"
  303. EOF
  304. }
  305. linetoc_ust()
  306. {
  307. local name args argnames fmt
  308. name=$(get_name "$1")
  309. args=$(get_args "$1")
  310. argnames=$(get_argnames "$1", ",")
  311. [ -z "$argnames" ] || argnames=", $argnames"
  312. fmt=$(get_fmt "$1")
  313. cat <<EOF
  314. DEFINE_TRACE(ust_$name);
  315. static void ust_${name}_probe($args)
  316. {
  317. trace_mark(ust, $name, $fmt$argnames);
  318. }
  319. EOF
  320. # Collect names for later
  321. names="$names $name"
  322. }
  323. linetoc_end_ust()
  324. {
  325. cat <<EOF
  326. static void __attribute__((constructor)) trace_init(void)
  327. {
  328. EOF
  329. for name in $names; do
  330. cat <<EOF
  331. register_trace_ust_$name(ust_${name}_probe);
  332. EOF
  333. done
  334. echo "}"
  335. }
  336. linetoh_begin_dtrace()
  337. {
  338. cat <<EOF
  339. #include "trace-dtrace.h"
  340. EOF
  341. }
  342. linetoh_dtrace()
  343. {
  344. local name args argnames nameupper
  345. name=$(get_name "$1")
  346. args=$(get_args "$1")
  347. argnames=$(get_argnames "$1", ",")
  348. nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
  349. # Define an empty function for the trace event
  350. cat <<EOF
  351. static inline void trace_$name($args) {
  352. if (QEMU_${nameupper}_ENABLED()) {
  353. QEMU_${nameupper}($argnames);
  354. }
  355. }
  356. EOF
  357. }
  358. linetoh_end_dtrace()
  359. {
  360. return
  361. }
  362. linetoc_begin_dtrace()
  363. {
  364. return
  365. }
  366. linetoc_dtrace()
  367. {
  368. # No need for function definitions in dtrace backend
  369. return
  370. }
  371. linetoc_end_dtrace()
  372. {
  373. return
  374. }
  375. linetod_begin_dtrace()
  376. {
  377. cat <<EOF
  378. provider qemu {
  379. EOF
  380. }
  381. linetod_dtrace()
  382. {
  383. local name args
  384. name=$(get_name "$1")
  385. args=$(get_args "$1")
  386. # DTrace provider syntax expects foo() for empty
  387. # params, not foo(void)
  388. if [ "$args" = "void" ]; then
  389. args=""
  390. fi
  391. # Define prototype for probe arguments
  392. cat <<EOF
  393. probe $name($args);
  394. EOF
  395. }
  396. linetod_end_dtrace()
  397. {
  398. cat <<EOF
  399. };
  400. EOF
  401. }
  402. linetostap_begin_dtrace()
  403. {
  404. return
  405. }
  406. linetostap_dtrace()
  407. {
  408. local i arg name args arglist
  409. name=$(get_name "$1")
  410. args=$(get_args "$1")
  411. arglist=$(get_argnames "$1", "")
  412. # Define prototype for probe arguments
  413. cat <<EOF
  414. probe $probeprefix.$name = process("$binary").mark("$name")
  415. {
  416. EOF
  417. i=1
  418. for arg in $arglist
  419. do
  420. # 'limit' is a reserved keyword
  421. if [ "$arg" = "limit" ]; then
  422. arg="_limit"
  423. fi
  424. cat <<EOF
  425. $arg = \$arg$i;
  426. EOF
  427. i="$((i+1))"
  428. done
  429. cat <<EOF
  430. }
  431. EOF
  432. }
  433. linetostap_end_dtrace()
  434. {
  435. return
  436. }
  437. # Process stdin by calling begin, line, and end functions for the backend
  438. convert()
  439. {
  440. local begin process_line end str disable
  441. begin="lineto$1_begin_$backend"
  442. process_line="lineto$1_$backend"
  443. end="lineto$1_end_$backend"
  444. "$begin"
  445. while read -r str; do
  446. # Skip comments and empty lines
  447. test -z "${str%%#*}" && continue
  448. echo
  449. # Process the line. The nop backend handles disabled lines.
  450. if has_property "$str" "disable"; then
  451. "lineto$1_nop" "$str"
  452. else
  453. "$process_line" "$str"
  454. fi
  455. done
  456. echo
  457. "$end"
  458. }
  459. tracetoh()
  460. {
  461. cat <<EOF
  462. #ifndef TRACE_H
  463. #define TRACE_H
  464. /* This file is autogenerated by tracetool, do not edit. */
  465. #include "qemu-common.h"
  466. EOF
  467. convert h
  468. echo "#endif /* TRACE_H */"
  469. }
  470. tracetoc()
  471. {
  472. echo "/* This file is autogenerated by tracetool, do not edit. */"
  473. convert c
  474. }
  475. tracetod()
  476. {
  477. if [ $backend != "dtrace" ]; then
  478. echo "DTrace probe generator not applicable to $backend backend"
  479. exit 1
  480. fi
  481. echo "/* This file is autogenerated by tracetool, do not edit. */"
  482. convert d
  483. }
  484. tracetostap()
  485. {
  486. if [ $backend != "dtrace" ]; then
  487. echo "SystemTAP tapset generator not applicable to $backend backend"
  488. exit 1
  489. fi
  490. if [ -z "$binary" ]; then
  491. echo "--binary is required for SystemTAP tapset generator"
  492. exit 1
  493. fi
  494. if [ -z "$probeprefix" -a -z "$targettype" ]; then
  495. echo "--target-type is required for SystemTAP tapset generator"
  496. exit 1
  497. fi
  498. if [ -z "$probeprefix" -a -z "$targetarch" ]; then
  499. echo "--target-arch is required for SystemTAP tapset generator"
  500. exit 1
  501. fi
  502. if [ -z "$probeprefix" ]; then
  503. probeprefix="qemu.$targettype.$targetarch";
  504. fi
  505. echo "/* This file is autogenerated by tracetool, do not edit. */"
  506. convert stap
  507. }
  508. backend=
  509. output=
  510. binary=
  511. targettype=
  512. targetarch=
  513. probeprefix=
  514. until [ -z "$1" ]
  515. do
  516. case "$1" in
  517. "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
  518. "--binary") shift ; binary="$1" ;;
  519. "--target-arch") shift ; targetarch="$1" ;;
  520. "--target-type") shift ; targettype="$1" ;;
  521. "--probe-prefix") shift ; probeprefix="$1" ;;
  522. "-h" | "-c" | "-d") output="${1#-}" ;;
  523. "--stap") output="${1#--}" ;;
  524. "--check-backend") exit 0 ;; # used by ./configure to test for backend
  525. "--list-backends") # used by ./configure to list available backends
  526. echo "nop simple stderr ust dtrace"
  527. exit 0
  528. ;;
  529. *)
  530. usage;;
  531. esac
  532. shift
  533. done
  534. if [ "$backend" = "" -o "$output" = "" ]; then
  535. usage
  536. fi
  537. gen="traceto$output"
  538. "$gen"
  539. exit 0