@@ -150,9 +150,9 @@ The Pubsub system introduces several key advantages:
150
150
metadata to the subscribers. Actual type defined by ` chain ` .
151
151
152
152
2 . ** Publishing** : Publishers (such as intercept modules or the Self module)
153
- publish events by calling ` PS_PUBLISH(chain_id, type_id, void*, metadata_t*) ` . The
154
- publisher specifies the chain, event type, event payload, and a potentially
155
- ` NULL ` metadata object.
153
+ publish events by calling `PS_PUBLISH(chain_id, type_id, void* ,
154
+ metadata_t * )`. The publisher specifies the chain, event type, event payload,
155
+ and a potentially ` NULL ` metadata object.
156
156
157
157
3 . ** Callback Handling** : The callback function is where the action happens for
158
158
the subscriber. Upon receiving an event, the callback can inspect and process
@@ -403,3 +403,153 @@ on a per-thread basis. Each thread can store its own file descriptor in its TLS
403
403
space, ensuring that threads do not interfere with each other’s file operations.
404
404
A subscriber could intercept system calls like open or close, logging the event
405
405
and associating file descriptors with the correct thread’s TLS.
406
+
407
+
408
+ # 5. Interpose Modules
409
+
410
+ In addition to the core Dice components, several interpose modules are provided
411
+ with Dice. These modules are designed to intercept and modify the behavior of
412
+ various system functions, allowing for detailed monitoring, testing, and
413
+ debugging. Interposition is a powerful technique that allows developers to hook
414
+ into existing system calls and modify their behavior or capture specific events.
415
+
416
+
417
+ ## 5.1. What is Interposition?
418
+
419
+ Interposition refers to the technique of intercepting calls to system functions
420
+ or library functions and inserting custom behavior. In Dice, this technique is
421
+ applied to various system functions using shared libraries and dynamic linking
422
+ mechanisms like ` LD_PRELOAD ` .
423
+
424
+ By using interposition, Dice can intercept functions like ` pthread_create ` ,
425
+ ` malloc ` , ` free ` , and other system-level functions without modifying the source
426
+ code of the application.
427
+
428
+
429
+ ## 5.2. How Interposition Works with ` LD_PRELOAD `
430
+
431
+ The ` LD_PRELOAD ` environment variable is a mechanism in Unix-like systems that
432
+ allows users to load shared libraries before others. When an application is run,
433
+ the dynamic linker checks the ` LD_PRELOAD ` variable and loads any libraries
434
+ listed in it before the default system libraries. This allows Dice to interpose
435
+ on functions without modifying the application’s code or the system libraries
436
+ themselves.
437
+
438
+ Each interpose module in Dice targets a specific set of functions. For example,
439
+ ` mod-pthread_create ` module intercepts calls to ` pthread_create ` and
440
+ ` pthread_exit ` , while the ` mod-malloc ` intercepts memory allocation functions
441
+ like ` malloc ` , ` free ` , ` calloc ` , and ` realloc ` .
442
+
443
+ When an application calls an intercepted function, the corresponding interpose
444
+ module is triggered. For example, when ` pthread_create ` is called, the interpose
445
+ module publishes events using the Pubsub system. For example, when
446
+ ` pthread_create ` is intercepted, the event ` EVENT_THREAD_CREATE ` is published.
447
+ Via a trampoline function, passed to the readl ` pthread_create ` , the new thread
448
+ also publishes a ` EVENT_THREAD_INIT ` event. Similarly, events like
449
+ ` EVENT_MUTEX_LOCK ` , ` EVENT_MUTEX_UNLOCK ` , ` EVENT_MALLOC ` , and ` EVENT_FREE ` can
450
+ be intercepted and published to the appropriate chains.
451
+
452
+ Notes that on macOS the environment variable to control library preloading is
453
+ called ` DYLD_INSERT_LIBRARIES ` .
454
+
455
+ ## 5.3. Interpose Modules in Dice
456
+
457
+ - ` mod-pthread_create ` : Intercepts the ` pthread_create ` and ` pthread_join `
458
+ functions to manage thread initialization and finalization.
459
+
460
+ - ` mod-pthread_mutex ` : Intercepts mutex functions like ` pthread_mutex_lock ` ,
461
+ ` pthread_mutex_unlock ` , ` pthread_mutex_trylock ` , etc to monitor thread
462
+ synchronization events via mutexes.
463
+
464
+ - ` mod-pthread_cond ` : Intercepts condition variable functions like
465
+ ` pthread_cond_wait ` , ` pthread_cond_signal ` , etc to track thread
466
+ synchronization on condition variables.
467
+
468
+ - ` mod-malloc ` : Intercepts memory allocation functions like ` malloc ` , ` free ` ,
469
+ ` calloc ` , and others to track memory usage and detect leaks or abnormal memory
470
+ access.
471
+
472
+ - ` mod-cxa ` : Intercepts functions related to exception handling, such as
473
+ ` __cxa_guard_acquire ` , ` __cxa_guard_release ` , and other related functions.
474
+
475
+ - ` mod-sem ` : Intercepts semaphore functions like ` sem_wait ` , ` sem_post ` , etc to
476
+ monitor semaphore operations.
477
+
478
+ - ` mod-tsan ` : Intercepts all functions exposed by ` libtsan.so ` to enable
479
+ fine-grained thread safety analysis.
480
+
481
+ By using these interpose modules, Dice can gather detailed execution data,
482
+ track thread behavior, monitor memory usage, and enable advanced testing and
483
+ debugging features.
484
+
485
+
486
+ # 6. Loading Modules
487
+
488
+ Dice is designed to be loaded as a shared library with ` LD_PRELOAD ` .
489
+ The core library in Dice has only the Pubsub and the Mempool modules inside.
490
+ Addtional modules can be loaded in two ways.
491
+
492
+
493
+ ## 6.1. Shared Library Modules
494
+
495
+ Consider a multithreaded application ` foo ` . To run ` foo ` with Dice the user
496
+ simply starts it with the following command:
497
+
498
+ ```
499
+ env LD_PRELOAD=/path/to/libdice.so foo <arg1>
500
+ ```
501
+
502
+ Additional modules can be loaded with the ` LD_PRELOAD ` variable as well:
503
+
504
+ ```
505
+ env LD_PRELOAD=/path/to/libdice.so:/path/to/mod-pthread_create.so:... foo <arg1>
506
+ ```
507
+
508
+ Subscription callbacks are internally kept as lists of function pointers. The
509
+ corresponding indirection cost has to be considered when deploying Dice in this
510
+ way.
511
+
512
+ ### Subscription Order
513
+
514
+ One has to be careful in which order the constructors of the modules are
515
+ executed. On NetBSD the constructors are executed left-to-right. Given a list
516
+ of libraries ` LD_PRELOAD=libdice.so:mod1.so:mod2.so ` , the subscribers in
517
+ ` mod1.so ` will be registered earlier than subscribers in ` mod2.so ` ; therefore,
518
+ callbacks in ` mod1.so ` will be called first. On Linux, the constructors are
519
+ executed right-to-left. So the opposite subscription order will result.
520
+
521
+ In general, the user has to figure out the order the constructors are called by
522
+ the linker and order the shared libraries accordingly.
523
+
524
+ ## 6.2. Monolithic Shared Library
525
+
526
+ Modules in Dice can also linked together with the core components in a single
527
+ shared library. In this configuration, each module is a compilation unit, i.e.,
528
+ a ` .o ` file. When compiling each of these files, the user should specify a
529
+ priority for the subscription order by passing ` -DDICE_XTOR_PRIO=VAL ` to the
530
+ compiler. ` VAL ` should be a number between 200 and 1000. The lower the value,
531
+ the higher the priority when subscribing chains.
532
+
533
+ Assume the user creates a library ` libmydice.so ` containing ` pubsub.o ` ,
534
+ ` mempool.o ` , ` mod-pthread_create.o ` and a user-defined module ` mymod.o ` . To load
535
+ this bundle, the user simply uses ` LD_PRELOAD ` :
536
+
537
+ ```
538
+ env LD_PRELOAD=/path/to/libmydice.so foo <arg1>
539
+ ```
540
+
541
+ If the user compiles all modules with LTO option, the resulting library can be
542
+ much faster than relying on the approach of section 6.1. Nevertheless, without
543
+ further steps, the resulting library above will use function pointers when
544
+ executing the callbacks of the subscribers.
545
+
546
+ ### Fast-Chain Module
547
+
548
+ Dice provides a auto-generated module called Fast-Chain module or ` fastch.o ` ,
549
+ which directly call the subscriber callbacks without relying on function
550
+ pointers. To do that, the Fast-Chain module employs large switch cases on the
551
+ ` chain_id ` , ` type_id ` and priority values. However, the ranges of these three
552
+ dimensions has to be limited to keep the size of the generated code manageable.
553
+
554
+ For instructions on how to use Fast-Chain, see the ` CMakeLists.txt ` inside
555
+ ` src/fastch ` .
0 commit comments