panwrap-util.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * © Copyright 2017 The BiOpenly Community
  3. *
  4. * This program is free software and is provided to you under the terms of the
  5. * GNU General Public License version 2 as published by the Free Software
  6. * Foundation, and any use by you of this program is subject to the terms
  7. * of such GNU licence.
  8. *
  9. * A copy of the licence is included with the program, and can also be obtained
  10. * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  11. * Boston, MA 02110-1301, USA.
  12. *
  13. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdbool.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <time.h>
  21. #include <ctype.h>
  22. #include "panwrap.h"
  23. #define HEXDUMP_COL_LEN 4
  24. #define HEXDUMP_ROW_LEN 16
  25. static bool enable_timestamps = false,
  26. enable_hexdump_trimming = true;
  27. static bool time_is_frozen = false;
  28. static struct timespec start_time;
  29. static struct timespec total_time_frozen, start_freeze_time, frozen_timestamp;
  30. static FILE *log_output;
  31. void
  32. panwrap_log_decoded_flags(const struct panwrap_flag_info *flag_info,
  33. u64 flags)
  34. {
  35. bool decodable_flags_found = false;
  36. panwrap_log_cont("0x%llx", flags);
  37. for (int i = 0; flag_info[i].name; i++) {
  38. if ((flags & flag_info[i].flag) != flag_info[i].flag)
  39. continue;
  40. if (!decodable_flags_found) {
  41. decodable_flags_found = true;
  42. panwrap_log_cont(" (");
  43. } else {
  44. panwrap_log_cont(" | ");
  45. }
  46. panwrap_log_cont("%s", flag_info[i].name);
  47. flags &= ~flag_info[i].flag;
  48. }
  49. if (decodable_flags_found) {
  50. if (flags)
  51. panwrap_log_cont(" | 0x%llx", flags);
  52. panwrap_log_cont(")");
  53. }
  54. }
  55. void
  56. panwrap_log_hexdump(const void *data, size_t size, const char *indent)
  57. {
  58. unsigned char *buf = (void *) data;
  59. char alpha[HEXDUMP_ROW_LEN + 1];
  60. unsigned int i;
  61. if (!data) {
  62. panwrap_log("NULL pointer dereference(hexdump)\n");
  63. return;
  64. }
  65. for (i = 0; i < size; i++) {
  66. if (!(i % HEXDUMP_ROW_LEN))
  67. panwrap_log("%s%08X", indent, (unsigned int) i);
  68. if (!(i % HEXDUMP_COL_LEN))
  69. panwrap_log_cont(" ");
  70. if (((void *) (buf + i)) < ((void *) data)) {
  71. panwrap_log_cont(" ");
  72. alpha[i % HEXDUMP_ROW_LEN] = '.';
  73. } else {
  74. panwrap_log_cont(" %02x", buf[i]);
  75. if (isprint(buf[i]) && (buf[i] < 0xA0))
  76. alpha[i % HEXDUMP_ROW_LEN] = buf[i];
  77. else
  78. alpha[i % HEXDUMP_ROW_LEN] = '.';
  79. }
  80. if ((i % HEXDUMP_ROW_LEN) == HEXDUMP_ROW_LEN - 1) {
  81. alpha[HEXDUMP_ROW_LEN] = 0;
  82. panwrap_log_cont("\t|%s|\n", alpha);
  83. }
  84. }
  85. if (i % HEXDUMP_ROW_LEN) {
  86. for (i %= HEXDUMP_ROW_LEN; i < HEXDUMP_ROW_LEN; i++) {
  87. panwrap_log_cont(" ");
  88. alpha[i] = '.';
  89. if (i == HEXDUMP_ROW_LEN - 1) {
  90. alpha[HEXDUMP_ROW_LEN] = 0;
  91. panwrap_log_cont("\t|%s|\n", alpha);
  92. }
  93. }
  94. }
  95. }
  96. /**
  97. * Same as panwrap_log_hexdump, but trims off sections of the memory that look
  98. * empty
  99. */
  100. void
  101. panwrap_log_hexdump_trimmed(const void *data, size_t size, const char *indent)
  102. {
  103. const char *d = data;
  104. off_t trim_offset;
  105. size_t trim_size = size;
  106. bool trimming = false;
  107. if (!enable_hexdump_trimming)
  108. goto out;
  109. if (!data) {
  110. panwrap_log("NULL pointer dereference(hexdump)\n");
  111. return;
  112. }
  113. /*
  114. * Find the last byte of the memory region that looks initialized,
  115. * starting from the end
  116. */
  117. for (trim_offset = size - 1; trim_offset != -1; trim_offset--) {
  118. if (d[trim_offset] != 0)
  119. break;
  120. }
  121. if (trim_offset < 0)
  122. goto out;
  123. trimming = true;
  124. trim_size = trim_offset + 1;
  125. out:
  126. panwrap_log_hexdump(data, trim_size, indent);
  127. if (trimming)
  128. panwrap_log("%s<0 repeating %zu times>\n",
  129. indent, size - trim_size);
  130. }
  131. /* glibc libraries are versioned. bionic libraries are not. If you use
  132. * something else, define it here.
  133. */
  134. #ifdef __GLIBC__
  135. #define LIBC_NAME "libc.so.6"
  136. #else
  137. #define LIBC_NAME "libc.so"
  138. #endif
  139. /**
  140. * Grab the location of a symbol from the system's libc instead of our
  141. * preloaded one
  142. */
  143. void *
  144. __rd_dlsym_helper(const char *name)
  145. {
  146. static void *libc_dl;
  147. void *func;
  148. if (!libc_dl)
  149. libc_dl = dlopen(LIBC_NAME, RTLD_LAZY);
  150. if (!libc_dl) {
  151. fprintf(stderr, "Failed to dlopen libc: %s\n", dlerror());
  152. exit(-1);
  153. }
  154. func = dlsym(libc_dl, name);
  155. if (!func) {
  156. fprintf(stderr, "Failed to find %s: %s\n", name, dlerror());
  157. exit(-1);
  158. }
  159. return func;
  160. }
  161. static void
  162. timespec_add(struct timespec *tp, const struct timespec *value)
  163. {
  164. tp->tv_sec += value->tv_sec;
  165. tp->tv_nsec += value->tv_nsec;
  166. if (tp->tv_nsec >= 1e+9) {
  167. tp->tv_sec++;
  168. tp->tv_nsec -= 1e+9;
  169. }
  170. }
  171. static void
  172. timespec_subtract(struct timespec *tp, const struct timespec *value)
  173. {
  174. tp->tv_sec -= value->tv_sec;
  175. tp->tv_nsec -= value->tv_nsec;
  176. if (tp->tv_nsec < 0) {
  177. tp->tv_sec--;
  178. tp->tv_nsec = 1e+9 + tp->tv_nsec;
  179. }
  180. }
  181. static inline void
  182. __get_monotonic_time(const char *file, int line, struct timespec *tp)
  183. {
  184. if (clock_gettime(CLOCK_MONOTONIC, tp)) {
  185. fprintf(stderr, "%s:%d:Failed to call clock_gettime: %s\n",
  186. file, line, strerror(errno));
  187. exit(1);
  188. }
  189. }
  190. #define get_monotonic_time(tp) __get_monotonic_time(__FILE__, __LINE__, tp);
  191. /*
  192. * When logging information to the console (or whatever our output is), we
  193. * obviously spend a good bit of time just outputting logs. The offsets in
  194. * timestamps that can be caused by this can cause the time difference between
  195. * one operation the driver performed and another to be rather misleading.
  196. *
  197. * So, in order to avoid this we "freeze time" whenever we have panwrap code
  198. * executing with a overhead that's noticeable between logging lines, so that
  199. * our timestamps never reflect the amount of time an application spent in
  200. * panwrap's code.
  201. *
  202. * tl;dr: any time that passes while frozen is removed from timestamps
  203. */
  204. void
  205. panwrap_freeze_time()
  206. {
  207. if (!enable_timestamps)
  208. return;
  209. get_monotonic_time(&start_freeze_time);
  210. time_is_frozen = true;
  211. /*
  212. * Calculate the actual timestamp using the time where we first froze,
  213. * since we know it won't change until we unfreeze time
  214. */
  215. frozen_timestamp = start_freeze_time;
  216. timespec_subtract(&frozen_timestamp, &start_time);
  217. timespec_subtract(&frozen_timestamp, &total_time_frozen);
  218. }
  219. void
  220. panwrap_unfreeze_time()
  221. {
  222. struct timespec time_spent_frozen;
  223. if (!enable_timestamps || !time_is_frozen)
  224. return;
  225. time_is_frozen = false;
  226. get_monotonic_time(&time_spent_frozen);
  227. timespec_subtract(&time_spent_frozen, &start_freeze_time);
  228. timespec_add(&total_time_frozen, &time_spent_frozen);
  229. }
  230. static inline void
  231. timestamp_get(struct timespec *tp)
  232. {
  233. if (time_is_frozen) {
  234. *tp = frozen_timestamp;
  235. return;
  236. }
  237. get_monotonic_time(tp);
  238. timespec_subtract(tp, &start_time);
  239. timespec_subtract(tp, &total_time_frozen);
  240. }
  241. void
  242. panwrap_log(const char *format, ...)
  243. {
  244. struct timespec tp;
  245. va_list ap;
  246. if (enable_timestamps) {
  247. timestamp_get(&tp);
  248. fprintf(log_output,
  249. "panwrap [%.8lf]: ", tp.tv_sec + tp.tv_nsec / 1e+9F);
  250. } else {
  251. fprintf(log_output, "panwrap: ");
  252. }
  253. va_start(ap, format);
  254. vfprintf(log_output, format, ap);
  255. va_end(ap);
  256. }
  257. /* Eventually this function might do more */
  258. void
  259. panwrap_log_cont(const char *format, ...)
  260. {
  261. va_list ap;
  262. va_start(ap, format);
  263. vfprintf(log_output, format, ap);
  264. va_end(ap);
  265. }
  266. static bool
  267. parse_env_bool(const char *env, bool def)
  268. {
  269. const char *val = getenv(env);
  270. if (!val)
  271. return def;
  272. if (strcmp(val, "1") == 0)
  273. return true;
  274. else if (strcmp(val, "0") == 0)
  275. return false;
  276. fprintf(stderr,
  277. "Invalid value for %s: %s\n"
  278. "Valid values are 0 or 1\n",
  279. env, val);
  280. exit(1);
  281. }
  282. static void __attribute__((constructor))
  283. panwrap_util_init()
  284. {
  285. const char *env;
  286. if (parse_env_bool("PANWRAP_ENABLE_TIMESTAMPS", false)) {
  287. enable_timestamps = true;
  288. if (clock_gettime(CLOCK_MONOTONIC, &start_time)) {
  289. fprintf(stderr,
  290. "Failed to call clock_gettime: %s\n",
  291. strerror(errno));
  292. exit(1);
  293. }
  294. }
  295. enable_hexdump_trimming = parse_env_bool("PANWRAP_ENABLE_HEXDUMP_TRIM",
  296. true);
  297. env = getenv("PANWRAP_OUTPUT");
  298. if (env) {
  299. /* Don't try to reopen stderr or stdout, that won't work */
  300. if (strcmp(env, "/dev/stderr") == 0) {
  301. log_output = stderr;
  302. } else if (strcmp(env, "/dev/stdout") == 0) {
  303. log_output = stdout;
  304. } else {
  305. log_output = fopen(env, "w+");
  306. if (!log_output) {
  307. fprintf(stderr, "Failed to open %s: %s\n",
  308. env, strerror(errno));
  309. exit(1);
  310. }
  311. }
  312. } else {
  313. log_output = stdout;
  314. }
  315. srand(time(NULL));
  316. }