1GOTCHA(1)                           Gotcha                           GOTCHA(1)
2
3
4

NAME

6       gotcha - Gotcha Documentation
7

OVERVIEW

9       Gotcha is an API that provides function wrapping, interposing a wrapper
10       function between a function and its callsites. Many tools rely on func‐
11       tion  wrapping  as a fundamental building block. For example, a perfor‐
12       mance analysis tool which wants to measure time an  application  spends
13       in  IO  might  put wrappers around "read()" and "write()" which trigger
14       stopwatches.
15
16       Tools traditionally implemented function wrapping with  the  LD_PRELOAD
17       environment  variable on glibc-based systems. This environment variable
18       allowed the tool to inject a tool library into the target  application.
19       Any  functions  that  the  tool  library exports, such as a "read()" or
20       "write()" function, will intercept calls to the matching function names
21       from  the original application. While powerful, the LD_PRELOAD approach
22       had several limitations:
23
24       • Tool libraries can have challenges  matching  ABI-compatibility  with
25         the application.
26
27       • Multiple tools cannot wrap the same function.
28
29       • The  set  of  wrapped functions are determined at tool build-time and
30         cannot be changed in response to application behavior.
31
32       Gotcha addresses these limitations by providing  an  API  for  function
33       wrapping. Tool libraries make wrapping requests to Gotcha that say, for
34       example, “wrap all calls to the read()  function  with  my  tool_read()
35       function,  and  give  me  a  function  pointer to the original read().”
36       Gotcha’s API allows tool wrapping decisions to be made at runtime,  and
37       it  handles cases of multiple tools wrapping the same function. It does
38       not, however, provide any new mechanisms for injecting the tool library
39       into an application. Gotcha-based tools should be added to the applica‐
40       tion at link-time or injected with LD_PRELOAD.
41
42       Gotcha works by rewriting the Global Offset Table (GOT) that links  in‐
43       ter-library  callsites  and  variable references to their targets.  Be‐
44       cause of this Gotcha cannot wrap intra-library calls (such as a call to
45       a static function in C) or calls in statically-linked binaries.  Binary
46       rewriting technology such as DyninstAPI is more appropriate  for  these
47       use cases.
48

DEFINITIONS

50       This section defines some terms used throughout the document.
51
52   GOT
53       The  Global  Offset Table, or GOT, is a section of a computer program's
54       (executables and shared libraries) memory used to enable computer  pro‐
55       gram  code compiled as an ELF file to run correctly, independent of the
56       memory address where the program's code or data is loaded  at  runtime.
57       More details can be read at GOT Documentation.
58
59   ELF
60       In  computing,  the  Executable  and  Linkable Format[2] (ELF, formerly
61       named Extensible Linking Format), is a common standard file format  for
62       executable files, object code, shared libraries, and core dumps.
63
64   LD_PRELOAD
65       LD_PRELOAD  is  a  powerful  and  advanced feature in the Linux dynamic
66       linker that allows users to preload shared object files  into  the  ad‐
67       dress space of a process.  Read more at LD_PRELOAD Documentation.
68
69   ABI-compatibility
70       An  application  binary interface (ABI) is an interface between two bi‐
71       nary program modules. An ABI defines how data  structures  or  computa‐
72       tional  routines  are  accessed  in machine code, which is a low-level,
73       hardware-dependent format.
74

LIMITATIONS

76   General Limitations
77   Operating system support
78       As the ELF is the file format  used  for  .o  object  files,  binaries,
79       shared  libraries  and  core dumps in Linux.  We currently only support
80       Linux OS.
81
82   Intra and Intra-library calls
83       Gotcha works by rewriting the Global Offset Table (GOT) that links  in‐
84       ter-library  callsites  and  variable references to their targets.  Be‐
85       cause of this Gotcha cannot wrap intra-library calls (such as a call to
86       a static function in C) or calls in statically-linked binaries.  Binary
87       rewriting technology such as DyninstAPI is more appropriate  for  these
88       use  cases.   Additionally,  the function pointer wrapping feature with
89       GOTCHA only applies to function pointers created after  wrapping  func‐
90       tions.   The  function  pointers  created  before wrapping would not be
91       wrapped by gotcha.
92

BUILD GOTCHA

94       This section describes how to build GOTCHA, and what configure time op‐
95       tions are available.
96
97       There are two build options:
98
99       • build GOTCHA with Spack, and
100
101       • build GOTCHA with cmake
102
103
104                                        ----
105
106
107
108   Build GOTCHA with Spack
109       One  may  install  GOTCHA  with Spack.  If you already have Spack, make
110       sure you have the latest release.  If you use a clone of the Spack  de‐
111       velop branch, be sure to pull the latest changes.
112
113   Install Spack
114          $ git clone https://github.com/spack/spack
115          $ # create a packages.yaml specific to your machine
116          $ . spack/share/spack/setup-env.sh
117
118       Use  Spack's  shell support to add Spack to your PATH and enable use of
119       the spack command.
120
121   Build and Install GOTCHA
122          $ spack install gotcha
123          $ spack load gotcha
124
125       If the most recent changes on the development branch ('dev') of  GOTCHA
126       are desired, then do spack install gotcha@develop.
127
128       ATTENTION:
129          The  initial  install could take a while as Spack will install build
130          dependencies (autoconf, automake, m4, libtool,  and  pkg-config)  as
131          well  as any dependencies of dependencies (cmake, perl, etc.) if you
132          don't already have these dependencies  installed  through  Spack  or
133          haven't  told  Spack where they are locally installed on your system
134          (i.e., through a custom packages.yaml).  Run spack  spec  -I  gotcha
135          before installing to see what Spack is going to do.
136
137
138                                        ----
139
140
141
142   Build GOTCHA with CMake
143       Download  the latest GOTCHA release from the Releases page or clone the
144       develop    branch    ('develop')    from    the    GOTCHA    repository
145       https://github.com/LLNL/GOTCHA.
146
147          cmake . -B build -DCMAKE_INSTALL_PREFIX=<where you want to install GOTCHA>
148          cmake --build build
149          cmake --install build
150
151
152                                        ----
153
154
155

GOTCHA API

157       This section describes how to use the GOTCHA API in an application.
158
159
160                                        ----
161
162
163
164   Include the GOTCHA Header
165       In C or C++ applications, include gotcha.h.
166
167          #include <gotcha.h>
168
169   Define your Gotcha wrappee
170       Gotcha  wrappee enables the application to call the function it wrapped
171       using GOTCHA.
172
173          static gotcha_wrappee_handle_t wrappee_fputs_handle;
174
175   Define your function wrapper
176       The function wrapper for wrapping functions from shared libraries.
177
178          static int fputs_wrapper(const char *str, FILE *f) {
179            // insert clever tool logic here
180            typeof(&fputs_wrapper) wrappee_fputs = gotcha_get_wrappee(wrappee_fputs_handle); // get my wrappee from Gotcha
181            return wrappee_fputs(str, f); //wrappee_fputs was directed to the original fputs by GOTCHA
182          }
183
184   Define GOTCHA bindings
185       GOTCHA works on binding a function name, wrapper function, and  wrappee
186       handle.  Gotcha works on triplets containing this information.
187
188          struct gotcha_binding_t wrap_actions [] = {
189            { "fputs", fputs_wrapper, &wrappee_fputs_handle },
190          };
191
192   Wrap the binding calls
193       To  initiate  gotcha  with the bindings defined in last step, tools can
194       call the gotcha_wrap function.  This function should be  called  before
195       any  interception  is  expected  by  the tool.  Some popular places for
196       calling this are gnu constructor or the start of  main  function.   The
197       function will always be successful and would never throw error.
198
199          gotcha_error_t gotcha_wrap(wrap_actions,
200                      sizeof(wrap_actions)/sizeof(struct gotcha_binding_t), // number of bindings
201                      "my_tool_name");
202
203       Multiple gotcha_wrap Caveat
204
205       We  allow  tools  to  bind different set of functions to different tool
206       names through multiple  gotcha_wrap  calls.   However,  a  tool  within
207       GOTCHA  is designed to layer or prioritize the order of functions bind‐
208       ing same symbol name.  For instance, if multiple tools bind  the  fputs
209       functions, then GOTCHA layers them to call one after the other with the
210       lowest level being the system call.  In this case, tools can prioritize
211       which  tools go first or second at runtime to determine the wrapper or‐
212       der for GOTCHA.  If an tool uses multiple bindings then  they  have  to
213       set  priority  to different bindings identified using tool_name defined
214       within the same tool.
215
216       ATTENTION:
217          The gotcha_wrap  function  modifies  the  gotcha_binding_t  wrap_ac‐
218          tions[]  provided by the user.  GOTCHA does not create a copy of the
219          binding functions and is the responsibility of the user to  maintain
220          this binding.
221
222   Set priority of tool binding
223       To   set   priority   of   tool   within   GOTCHA,  tools  can  utilize
224       gotcha_set_priority function.  The priority is an  integer  value  with
225       lower  values  are for inner most call.  The lowest layer is the system
226       call followed by GOTCHA layer and finally other tools based  on  prior‐
227       ity.   The  API would never fail. If it return GOTCHA_INTERNAL as error
228       then there was issue with memory allocation of tool.  If multiple tools
229       have  same  priority then they are wrapper in FIFO order with the first
230       tool being the inner-most wrapper.  Without calling this  API  the  de‐
231       fault priority given to each tool is -1.
232
233          gotcha_error_t gotcha_set_priority(const char* tool_name,
234                                             int priority);
235
236   Get priority of tool binding
237       This API gets the priority of the tool. This could be default or as as‐
238       signed by the tool.
239
240          gotcha_error_t gotcha_get_priority(const char* tool_name,
241                                             int *priority);
242
243   Get the wrapped function from GOTCHA stack
244       This API return the wrapped function to call based on the  tool's  han‐
245       dle.   The tools handle is used to locate the next element of the wrap‐
246       per stack and return the function.  Returns  the  ptr  of  the  wrapped
247       function.
248
249          void* gotcha_get_wrappee(gotcha_wrappee_handle_t handle);
250
251   Filter libraries
252       Within  GOTCHA,  even bound symbol is updated in the GOT table for each
253       shared library loaded within the tool.  In some cases, tools might  not
254       want  to  update  these  symbols  on  some libraries.  For these cases,
255       GOTCHA has a series of filter functions that can assist tools to define
256       which  libraries should be updated.  CAUTION: this could lead to behav‐
257       iors where calls from these  libraries  would  not  be  intercepted  by
258       GOTCHA wrappers and need to handled by the tool.
259
260   Filter by Name
261       This API allows GOTCHA to include only libraries given specified by the
262       user.  This could be a partial match of string contains as  defined  by
263       strstr function in C.
264
265          void gotcha_filter_libraries_by_name(const char* nameFilter);
266
267   Filter if Last
268       This  API allows GOTCHA to include only the last library defined in the
269       linker of the tool.
270
271          void gotcha_only_filter_last();
272
273   Filter by user defined function
274       This API allows users to define a function that selected the  libraries
275       that  user  wants  to  intercept.   The  function  should  take  struct
276       link_map* as input and return true if it should be wrapped  by  GOTCHA.
277       TIP: the library name can be accessed by map->l_name.
278
279          void gotcha_set_library_filter_func(int(*new_func)(struct link_map*));
280
281   Restore default filter of GOTCHA
282       The  default  filter of gotcha selects all libraries loaded. This func‐
283       tion set the default filter back for GOTCHA.
284
285          void gotcha_restore_library_filter_func();
286

EXAMPLE PROGRAMS

288       This example shows how to use gotcha to wrap the open  and  fopen  libc
289       calls.  This  example is self-contained, though in typical gotcha work‐
290       flows the gotcha calls would be in a separate library from the applica‐
291       tion.
292
293       The  example  logs  the  parameters and return result of every open and
294       fopen call to stderr.
295
296          #include <stdio.h>
297          #include <sys/types.h>
298          #include <sys/stat.h>
299          #include <fcntl.h>
300
301          #include "gotcha/gotcha.h"
302
303          typedef int (*open_fptr)(const char *pathname, int flags, mode_t mode);
304          typedef FILE* (*fopen_fptr)(const char *pathname, const char *mode);
305
306          static gotcha_wrappee_handle_t open_handle;
307          static gotcha_wrappee_handle_t fopen_handle;
308
309          static int open_wrapper(const char *pathname, int flags, mode_t mode) {
310            open_fptr open_wrappee = (open_fptr) gotcha_get_wrappee(open_handle);
311            int result = open_wrappee(pathname, flags, mode);
312            fprintf(stderr, "open(%s, %d, %u) = %d\n",
313                    pathname, flags, (unsigned int) mode, result);
314            return result;
315          }
316
317          static FILE *fopen_wrapper(const char *path, const char *mode) {
318            fopen_fptr fopen_wrappee = (fopen_fptr) gotcha_get_wrappee(fopen_handle);
319            FILE *result = fopen_wrappee(path, mode);
320            fprintf(stderr, "fopen(%s, %s) = %p\n",
321                    path, mode, result);
322            return result;
323          }
324
325          static gotcha_binding_t bindings[] = {
326            { "open", open_wrapper, &open_handle },
327            { "fopen", fopen_wrapper, &fopen_handle }
328          };
329
330          int main(int argc, char *argv[]) {
331            gotcha_wrap(bindings, 2, "demotool");
332
333            open("/dev/null", O_RDONLY);
334            open("/dev/null", O_WRONLY | O_CREAT | O_EXCL);
335            fopen("/dev/random", "r");
336            fopen("/does/not/exist", "w");
337
338            return 0;
339          }
340
341       The fundamental data structure in the Gotcha API  is  the  gotcha_bind‐
342       ing_t  table,  which  is  shown  in lines 29-32. This table states that
343       calls to open should be rerouted to call  open_wrapper,  and  similarly
344       for fopen and fopen_wrapper. The original open and fopen functions will
345       still be accessible via the handles open_handle and fopen_handle.
346
347       The binding table is passed to Gotcha on line 36, which specifies there
348       are  two entries in the table and that these are part of the “demotool”
349       tool. The open_handle and fopen_handle variables are  updated  by  this
350       call to gotcha_wrap and can now be used to look up function pointers to
351       the original open and fopen calls.
352
353       The subsequent callsites to open and fopen on  lines  37-40  are  redi‐
354       rected  to  respectively  call  open_wrapper and fopen_wrapper on lines
355       14-20 and 22-27. Each of these functions looks up the original open and
356       fopen functions using the gotcha_get_wrappee API call and the open_han‐
357       dle and fopen_handle on lines 15 and 23.
358
359       The wrappers call then call the underlying  functions  open  and  fopen
360       functions  on  lines 16 and 24. The print the parameters and results of
361       these calls on lines 17 and 25 and return.
362
363       Note that this example skips proper error  handling  for  brevity.  The
364       call  to  gotcha_wrap  could have failed to find instances of fopen and
365       open in the process, which would have led to an error return. The calls
366       to fprintf on lines 17 and 25 are stomping on the value of errno, which
367       could be set in the open and fopen calls on lines 16 and 24.
368

STYLE GUIDES

370   Coding Conventions
371       GOTCHA follows the Google coding style.  Please  run  git  clang-format
372       --diff  HEAD~1 -q to check your patch for style problems before submit‐
373       ting it for review.
374
375   Styling Code
376       The clang-format tool can be used to apply much of  the  required  code
377       styling used in the project.
378
379       To apply style to the source file foo.c:
380
381          clang-format --style=Google --Werror foo.c
382
383       The .clang-format file specifies the options used for this project. For
384       a    full    list    of    available    clang-format    options,    see
385       https://clang.llvm.org/docs/ClangFormat.html.
386
387   Verifying Style Checks
388       To  check  that uncommitted changes meet the coding style, use the fol‐
389       lowing command:
390
391          git clang-format --diff HEAD~1 -q
392
393       TIP:
394          This command will only check specific changes and additions to files
395          that  are  already  tracked by git. Run the command git add -N [<un‐
396          tracked_file>...] first in order to style check new files as well.
397
398
399                                        ----
400
401
402
403   Commit Message Format
404       Commit messages for new changes must meet the following guidelines:
405
406       • In 50 characters or less, provide a summary  of  the  change  as  the
407         first line in the commit message.
408
409       • A  body  which  provides  a  description of the change. If necessary,
410         please summarize important information such as why the  proposed  ap‐
411         proach  was  chosen or a brief description of the bug you are resolv‐
412         ing. Each line of the body must be 72 characters or less.
413
414       An example commit message for new changes is provided below.
415
416          Capitalized, short (50 chars or less) summary
417
418          More detailed explanatory text, if necessary.  Wrap it to about 72
419          characters or so.  In some contexts, the first line is treated as the
420          subject of an email and the rest of the text as the body.  The blank
421          line separating the summary from the body is critical (unless you omit
422          the body entirely); tools like rebase can get confused if you run the
423          two together.
424
425          Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
426          or "Fixes bug."  This convention matches up with commit messages generated
427          by commands like git merge and git revert.
428
429          Further paragraphs come after blank lines.
430
431          - Bullet points are okay
432
433          - Typically a hyphen or asterisk is used for the bullet, followed by a
434            single space, with blank lines in between, but conventions vary here
435
436          - Use a hanging indent
437

TESTING GUIDE

439       We can never have enough testing. Any additional tests  you  can  write
440       are always greatly appreciated.
441
442   Unit Tests
443       Testing  new  core  features within GOTCHA should be implemented in the
444       test/unit/gotcha_unit_tests.c using the check framework as  defined  in
445       https://libcheck.github.io/check.
446
447   Create a new test
448       We can create a new test using START_TEST and END_TEST macros.
449
450          START_TEST(sample_test){
451          }
452          END_TEST
453
454   Create a new suite
455       These new tests can be added to new suite with code similar to the fol‐
456       lowing.  To add to existing suite, we need use  tcase_add_test  api  to
457       add the test function to the suite.
458
459          Suite* gotcha_sample_suite(){
460            Suite* s = suite_create("Sample");
461            TCase* sample_case = configured_case_create("Basic tests");
462            tcase_add_test(sample_case, sample_test);
463            suite_add_tcase(s, sample_case);
464            return s;
465          }
466
467   Adding suite to runner
468       Within  the  main  function  of  the test/unit/gotcha_unit_tests.c, the
469       gotcha_sample_suite can be added as follows.
470
471          Suite* sample_suite = gotcha_sample_suite();
472          SRunner* sample_runner = srunner_create(sample_suite);
473          srunner_run_all(sample_suite, CK_NORMAL);
474          num_fails += srunner_ntests_failed(sample_suite);
475
476   Testing tool specific usage of GOTCHA
477       We should use custom test cases where we are testing the API for GOTCHA
478       for  specific features such as filtering libraries, main function bind‐
479       ings, etc.  These test cases can be stored within the test folder. Look
480       at  existing  examples such as test/stack and test/dlopen to understand
481       how we can implement these tests.
482
483       Once you add a self containing test case within test, we can add it  to
484       the test/CMakeLists.txt.
485
486Index
487
488Module Index
489
490Search Page
491

AUTHOR

493       Hariharan Devarajan, David Poliakoff, Matt Legendre
494
496       2023, Lawrence Livermore National Security, LLC
497
498
499
500
5011.0                              Nov 18, 2023                        GOTCHA(1)
Impressum