pastebin - collaborative debugging tool
rovema.kpaste.net RSS


Intercepting pthread_mutext_init() via LD_PRELOAD
Posted by Anonymous on Mon 10th Jul 2023 15:22
raw | new post
modification of post by Anonymous (view diff)

  1. + for i in pthread_mutex_attr_util/*
  2. + diff -u /dev/null pthread_mutex_attr_util/Makefile
  3. --- /dev/null   2023-07-10 02:44:06.720465928 +0200
  4. +++ pthread_mutex_attr_util/Makefile    2023-07-10 16:10:28.308408997 +0200
  5. @@ -0,0 +1,76 @@
  6. +#
  7. +# Makefile for LD_PRELOAD pthread_mutex_attr_util
  8. +#
  9. +# Written by Roland Mainz <roland.mainz@nrubsig.org>
  10. +#
  11. +
  12. +#
  13. +#
  14. +# ToDo:
  15. +# - cleanup (this Makefile is horrible and should actually use macros)
  16. +# - build 32bit and 64bit at the same time
  17. +#
  18. +
  19. +SHELL=/bin/ksh93
  20. +
  21. +CSTDFLAGS=-std=c17
  22. +CARCHFLAGS=-m32 # -m32 or -m64
  23. +CC=gcc # gcc or clang
  24. +
  25. +#
  26. +# misc
  27. +#
  28. +all:   tests pthread_mutex_attr_util_binaries.tar.bz2
  29. +
  30. +clean:
  31. +       rm -f \
  32. +               *.o \
  33. +               *.so \
  34. +               test1 \
  35. +               pthread_mutex_attr_util_wrapper \
  36. +               pthread_mutex_attr_util_binaries.tar.bz2
  37. +
  38. +#
  39. +# build shared library object for LD_PRELOAD
  40. +#
  41. +pthread_mutex_attr_util.o: pthread_mutex_attr_util.c
  42. +       $(CC) $(CSTDFLAGS) $(CARCHFLAGS) -Wall -g pthread_mutex_attr_util.c -fPIC -rdynamic -c -o pthread_mutex_attr_util.o
  43. +pthread_mutex_attr_util.so: pthread_mutex_attr_util.o
  44. +       $(CC) $(CSTDFLAGS) $(CARCHFLAGS) -Wall -g pthread_mutex_attr_util.o -fPIC -rdynamic -shared -ldl -lpthread -o pthread_mutex_attr_util.so
  45. +
  46. +#
  47. +# compile wrapper script
  48. +#
  49. +pthread_mutex_attr_util_wrapper: pthread_mutex_attr_util_wrapper.ksh
  50. +       shcomp pthread_mutex_attr_util_wrapper.ksh >pthread_mutex_attr_util_wrapper
  51. +       chmod a+x pthread_mutex_attr_util_wrapper
  52. +
  53. +#
  54. +# tests
  55. +#
  56. +
  57. +# -rdynamic is required for gcc so that we get accurate function
  58. +# names from |backtrace()|&co
  59. +test1: test1.c
  60. +       $(CC) $(CSTDFLAGS) $(CARCHFLAGS) -Wall -rdynamic -g test1.c -o test1
  61. +      
  62. +tests: test1 pthread_mutex_attr_util.so pthread_mutex_attr_util_wrapper
  63. +       @printf "# Begin tests.\n"
  64. +       ./pthread_mutex_attr_util_wrapper ./test1
  65. +       @printf "# End tests.\n"
  66. +
  67. +#
  68. +# package binaries
  69. +#
  70. +pthread_mutex_attr_util_binaries.tar.bz2: \
  71. +       pthread_mutex_attr_util.so \
  72. +       pthread_mutex_attr_util_wrapper \
  73. +       pthread_mutex_attr_util_wrapper.ksh \
  74. +       README.pthread_mutex_attr_util
  75. +       tar -cvf - pthread_mutex_attr_util.so \
  76. +               pthread_mutex_attr_util_wrapper \
  77. +               pthread_mutex_attr_util_wrapper.ksh \
  78. +               README.pthread_mutex_attr_util | \
  79. +               bzip2 -9 >"pthread_mutex_attr_util_binaries.tar.bz2"
  80. +
  81. +# EOF.
  82. + for i in pthread_mutex_attr_util/*
  83. + diff -u /dev/null pthread_mutex_attr_util/pthread_mutex_attr_util.c
  84. --- /dev/null   2023-07-10 02:44:06.720465928 +0200
  85. +++ pthread_mutex_attr_util/pthread_mutex_attr_util.c   2023-07-10 15:49:12.506481422 +0200
  86. @@ -0,0 +1,179 @@
  87. +/*
  88. + * pthread_mutex_attr_util.c
  89. + *
  90. + * Intercept pthread calls to |pthread_mutex_init()|) via LD_PRELOAD
  91. + * and check/set mutext attributes
  92. + *
  93. + * Example usage:
  94. + * $ ksh93 -c 'LD_PRELOAD="$PWD/pthread_mutex_attr_util.so" ./test_prog'
  95. + *
  96. + * Written by Roland Mainz <roland.mainz@nrubsig.org>
  97. + */
  98. +
  99. +#define _GNU_SOURCE 1 /* needed for |RTLD_NEXT| */
  100. +
  101. +#include <pthread.h>
  102. +#include <unistd.h>
  103. +#include <errno.h>
  104. +#include <stdlib.h>
  105. +#include <stdint.h>
  106. +#include <stdio.h>
  107. +#include <string.h>
  108. +#include <stdbool.h>
  109. +#include <dlfcn.h>
  110. +#include <execinfo.h>
  111. +
  112. +
  113. +/* misc macros */
  114. +#define STDERR_MSG(msg) \
  115. +       (void)write(STDERR_FILENO, (msg), strlen(msg))
  116. +#define BT_BUFF_ELEMENTS 256
  117. +#define MYMIN(a,b) (((a) < (b)) ? (a) : (b))
  118. +#define PTR2UINT64T(p) ((uint64_t)(((char *)((void *)(p)))-((char *)0)))
  119. +
  120. +
  121. +/* Our data */
  122. +struct pmau_data
  123. +{
  124. +       pthread_once_t init_once;
  125. +       int (*original_pthread_mutex_init)(pthread_mutex_t *restrict mutex,
  126. +               const pthread_mutexattr_t *restrict attr);
  127. +
  128. +       /* Configuration */
  129. +       bool verbose;
  130. +       bool print_backtrace;
  131. +       int num_backtrace_lines;
  132. +       bool enforce_prio_inherit;
  133. +       bool warn_no_prio_inherit;
  134. +};
  135. +
  136. +static struct pmau_data pmau_data = {
  137. +       .init_once                      = PTHREAD_ONCE_INIT,
  138. +       .original_pthread_mutex_init    = NULL,
  139. +       .verbose                        = false,
  140. +       .print_backtrace                = false,
  141. +       .num_backtrace_lines            = 8,
  142. +       .enforce_prio_inherit           = false,
  143. +       .warn_no_prio_inherit           = false,
  144. +};
  145. +
  146. +static
  147. +int getenv_int(const char *name, int default_value)
  148. +{
  149. +       const char *s;
  150. +      
  151. +       s = getenv(name);
  152. +       if (!s)
  153. +               return default_value;
  154. +       return (strtol(s, NULL, 10));
  155. +}
  156. +
  157. +static
  158. +void pmau_init(void)
  159. +{
  160. +       char mymessage[256];
  161. +
  162. +#define GET_PMAU_ENV_BOOL(name, defval) \
  163. +       ((getenv_int(name, (defval)) == 1)?true:false)
  164. +       pmau_data.verbose               = GET_PMAU_ENV_BOOL("PMAU_VERBOSE", 1);
  165. +       pmau_data.print_backtrace       = GET_PMAU_ENV_BOOL("PMAU_PRINT_BACKTRACE", 1);
  166. +       pmau_data.num_backtrace_lines   = getenv_int("PMAU_NUM_BACKTRACE_LINES", 8);
  167. +       pmau_data.enforce_prio_inherit  = GET_PMAU_ENV_BOOL("PMAU_ENFORCE_PRIO_INHERIT", 0);
  168. +       pmau_data.warn_no_prio_inherit  = GET_PMAU_ENV_BOOL("PMAU_WARN_NO_PRIO_INHERIT", 1);
  169. +
  170. +       (void)snprintf(mymessage, sizeof(mymessage),
  171. +               "# pthread_mutex_attr_util.so: Once: init("
  172. +               "verbose=%d, "
  173. +               "backtrace=%d, "
  174. +               "enforce_prio_inherit=%d, "
  175. +               "warn_no_prio_inherit=%d)\n",
  176. +               (int)pmau_data.verbose,
  177. +               (int)pmau_data.print_backtrace,
  178. +               (int)pmau_data.enforce_prio_inherit,
  179. +               (int)pmau_data.warn_no_prio_inherit);
  180. +       STDERR_MSG(mymessage);
  181. +
  182. +       pmau_data.original_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init");
  183. +}
  184. +
  185. +
  186. +/*
  187. + * interceptor for |pthread_mutex_init()|
  188. + */
  189. +int pthread_mutex_init(pthread_mutex_t *restrict mutex,
  190. +               const pthread_mutexattr_t *restrict attr) {
  191. +       pthread_mutexattr_t *xattr = (pthread_mutexattr_t *)attr;
  192. +       int pmi_res;
  193. +       int pmi_errno;
  194. +
  195. +       (void)pthread_once(&pmau_data.init_once, pmau_init);
  196. +
  197. +       pthread_mutexattr_t myattr;
  198. +       bool myattr_used = false;
  199. +
  200. +       if (!xattr) {
  201. +               (void)pthread_mutexattr_init(&myattr);
  202. +               myattr_used = true;
  203. +               xattr = &myattr;
  204. +       }
  205. +
  206. +       int mutex_protocol = -666;
  207. +       (void)pthread_mutexattr_getprotocol(xattr, &mutex_protocol);
  208. +       if (mutex_protocol != PTHREAD_PRIO_INHERIT) {
  209. +               char msgbuff[1024]; /* fixed size, but no |malloc()| allowed here */
  210. +
  211. +               if (pmau_data.enforce_prio_inherit || pmau_data.warn_no_prio_inherit) {
  212. +                       if (pmau_data.enforce_prio_inherit) {
  213. +                               (void)pthread_mutexattr_setprotocol(xattr, PTHREAD_PRIO_INHERIT);
  214. +                               if (pmau_data.verbose) {
  215. +                                       (void)snprintf(msgbuff,
  216. +                                               sizeof(msgbuff),
  217. +                                               "# pthread_mutex_attr_util.so: "
  218. +                                               "PTHREAD_PRIO_INHERIT enforced "
  219. +                                               "for mutex=0x%llx, was protocol=%d\n",
  220. +                                               PTR2UINT64T(mutex),
  221. +                                               mutex_protocol);
  222. +                                       STDERR_MSG(msgbuff);
  223. +                               }
  224. +                       }
  225. +                       else
  226. +                       {
  227. +                               (void)snprintf(msgbuff,
  228. +                                       sizeof(msgbuff),
  229. +                                       "# pthread_mutex_attr_util.so: "
  230. +                                       "PTHREAD_PRIO_INHERIT not set "
  231. +                                       "for mutex=0x%llx, protocol=%d\n",
  232. +                                       PTR2UINT64T(mutex),
  233. +                                       mutex_protocol);
  234. +                               STDERR_MSG(msgbuff);
  235. +                       }
  236. +              
  237. +                       if (pmau_data.print_backtrace) {
  238. +                               /*
  239. +                                * print backtrace
  240. +                                * Might cause a gross mix of marmelade if multiple
  241. +                                * threads write at the same time, and syslog is used
  242. +                                * to log stderr
  243. +                                * To limit the madness we restrict the backtrace to
  244. +                                * four lines
  245. +                                */
  246. +                               void *bt_buffer[BT_BUFF_ELEMENTS];
  247. +                               int nptrs;
  248. +                               nptrs = backtrace(bt_buffer, BT_BUFF_ELEMENTS);
  249. +                               backtrace_symbols_fd(bt_buffer,
  250. +                                       MYMIN(nptrs, pmau_data.num_backtrace_lines),
  251. +                                       STDERR_FILENO);
  252. +                       }
  253. +               }
  254. +       }
  255. +
  256. +       pmi_res = (*pmau_data.original_pthread_mutex_init)(mutex, xattr);
  257. +       pmi_errno = errno;
  258. +
  259. +       if (myattr_used) {
  260. +               (void)pthread_mutexattr_destroy(&myattr);
  261. +       }
  262. +
  263. +       errno = pmi_errno;
  264. +       return pmi_res;
  265. +}
  266. + for i in pthread_mutex_attr_util/*
  267. + diff -u /dev/null pthread_mutex_attr_util/pthread_mutex_attr_util_wrapper.ksh
  268. --- /dev/null   2023-07-10 02:44:06.720465928 +0200
  269. +++ pthread_mutex_attr_util/pthread_mutex_attr_util_wrapper.ksh 2023-07-10 16:16:25.147396466 +0200
  270. @@ -0,0 +1,30 @@
  271. +#!/bin/ksh93
  272. +
  273. +#
  274. +# pthread_mutex_attr_util wrapper script
  275. +#
  276. +# Written by Roland Mainz <roland.mainz@nrubsig.org>
  277. +#
  278. +
  279. +function add_ld_preload
  280. +{
  281. +       [[ -x "$1" ]] && LD_PRELOAD="$1:${LD_PRELOAD-}"
  282. +}
  283. +
  284. +add_ld_preload "$PWD/pthread_mutex_attr_util.so"
  285. +add_ld_preload "/usr/lib/pthread_mutex_attr_util/pthread_mutex_attr_util.so"
  286. +
  287. +export LD_PRELOAD
  288. +
  289. +#
  290. +# ToDo: Add option parsing
  291. +#
  292. +
  293. +#
  294. +# make sure we re-use the PID so we can squeeze this script
  295. +# between the caller and the original binary, so that the
  296. +# caller doesn't notice it
  297. +#
  298. +exec "$@"
  299. +
  300. +# EOF.
  301. + for i in pthread_mutex_attr_util/*
  302. + diff -u /dev/null pthread_mutex_attr_util/README.pthread_mutex_attr_util
  303. --- /dev/null   2023-07-10 02:44:06.720465928 +0200
  304. +++ pthread_mutex_attr_util/README.pthread_mutex_attr_util      2023-07-10 16:17:35.366410725 +0200
  305. @@ -0,0 +1,25 @@
  306. +#
  307. +# README.pthread_mutex_attr_util
  308. +#
  309. +
  310. +# FIXME: Write better README
  311. +
  312. +pthread_mutex_attr_util - simple utility to check/set pthread mutext attributes
  313. +
  314. +** Example usage 1:
  315. +$ ksh93 -c 'LD_PRELOAD="$PWD/pthread_mutex_attr_util.so" ./test_prog'
  316. +
  317. +** Example usage 2:
  318. +# (this assumes that pthread_mutex_attr_util.so is in $PWD or
  319. +# /usr/lib/pthread_mutex_attr_util/pthread_mutex_attr_util.so)
  320. +$ ./pthread_mutex_attr_util_wrapper ./test_prog'
  321. +
  322. +
  323. +** Environment variables:
  324. +"PMAU_VERBOSE" ("0" or "1") - enables verbose messages
  325. +"PMAU_PRINT_BACKTRACE" ("0" or "1") - print stack trace
  326. +"PMAU_NUM_BACKTRACE_LINES" (integer) - number of lines per stack trace
  327. +"PMAU_ENFORCE_PRIO_INHERIT" ("0" or "1") - enforce PTHREAD_PRIO_INHERIT
  328. +"PMAU_WARN_NO_PRIO_INHERIT" ("0" or "1") - warn if PTHREAD_PRIO_INHERIT is not set
  329. +
  330. +# EOF.
  331. + for i in pthread_mutex_attr_util/*
  332. + diff -u /dev/null pthread_mutex_attr_util/test1.c
  333. --- /dev/null   2023-07-10 02:44:06.720465928 +0200
  334. +++ pthread_mutex_attr_util/test1.c     2023-07-10 14:35:40.903932290 +0200
  335. @@ -0,0 +1,30 @@
  336. +/*
  337. + * test1 for pthread_mutex_attr_util.c
  338. + *
  339. + */
  340. +
  341. +#include <stdlib.h>
  342. +#include <stdio.h>
  343. +#include <pthread.h>
  344. +#include <errno.h>
  345. +
  346. +void run_tests1(void)
  347. +{
  348. +       pthread_mutex_t mutex1;
  349. +       pthread_mutex_t mutex2;
  350. +      
  351. +       (void)pthread_mutex_init(&mutex1, NULL);
  352. +       perror("pthread_mutex_init(mutex1) result");
  353. +
  354. +       (void)pthread_mutex_init(&mutex2, NULL);
  355. +       perror("pthread_mutex_init(mutex2) result");
  356. +}
  357. +
  358. +int main(int ac, char *av[])
  359. +{
  360. +       (void)puts("# start.");
  361. +       run_tests1();
  362. +       (void)puts("# end.");
  363. +
  364. +       return EXIT_SUCCESS;
  365. +}

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at