1
2recorder_configure_type(3)     Recorder Library     recorder_configure_type(3)
3
4
5

NAME

7       record_configure_type - Configure format characters for event records
8
9
10

SYNOPSIS

12       #include <recorder/recorder.h>
13
14       typedef size_t (*recorder_type_fn)(intptr_t trace,
15                                          const char *format,
16                                           char *buffer,
17                                           size_tlength,
18                                           uintptr_tdata);
19       recorder_type_fn   recorder_configure_type(uint8_tid, recorder_type_fntype);
20
21

DESCRIPTION

23       The  record_configure_type configures a type formatting character iden‐
24       tified by id that can then be used in record(3) format  strings.   This
25       is  normally  used  to add special extensions to the printf format that
26       deal with to frequently used data types in the program. In the  example
27       below,  we  use  record_configure_type('t', todo_format) so that the %t
28       format sequence will format struct todo * pointers.
29
30
31       The function identified by type is called to perform  the  actual  data
32       formatting. It receives the following arguments:
33
34
35       trace  is  the  tracing  value  associated to the recorder. This can be
36              used to implement safe pointer rendering  similar  to  %+s  i.e.
37              only derefrence the given pointer if you know that it is safe to
38              do so. Note that if the format string is %+id then the value  of
39              trace will be non-zero.
40
41
42       format is  the actual format string, which allows your type function to
43              handle format modifiers or precision indicators similar  to  the
44              way printf does.
45
46
47       buffer is the buffer where your function should write its output.
48
49
50       length is the amount of space available in the buffer.
51
52
53       data   is  the actual value stored in the recorder event, for example a
54              pointer to your data.
55
56
57

RETURN VALUE

59       The return value of recorder_configure_type() is the previous  function
60       handling the given format identifier.
61
62
63       The  type function should return the size it would have written, in the
64       same way snprintf(3) does, i.e. the number of characters that it  would
65       have written, irrespective of the size of the buffer.
66
67
68

EXAMPLES

70       The  following  program uses recorder_configure_type() to associate the
71       function todo_format() to the %t format sequence. The  function  inter‐
72       prets  its argument as a struct todo * pointer. The main program builds
73       a to-do list from command-line arguments, but it contains a subtle  bug
74       that causes it to crash if any of the arguments happens to be "crash".
75
76
77           #include <recorder/recorder.h>
78           #include <string.h>
79           #include <stdlib.h>
80           #include <stdio.h>
81
82           RECORDER(todo, 32, "To-Do List");
83
84           typedef struct todo
85           {
86               const char *name;
87               struct todo *next;
88           } todo;
89
90           size_t todo_format(intptr_t tracing,
91                              const char *format,
92                              char *buffer, size_t size,
93                              uintptr_t arg)
94           {
95               struct todo *t = (struct todo *) arg;
96               if (!tracing || !t)
97                   return snprintf(buffer, size, "%p", arg);
98               return snprintf(buffer, size, "todo@%p('%s')", t, t->name);
99           }
100
101           int main(int argc, char **argv)
102           {
103               int a;
104               todo *list = NULL;
105               int crash = 0;
106               recorder_dump_on_common_signals(0, 0);
107               recorder_configure_type('t', todo_format);
108               for (a = 1; a < argc; a++)
109               {
110                   record(todo, "Argument %d is '%+s'", a, argv[a]);
111                   todo *next = malloc(sizeof(todo));
112                   next->name = argv[a];
113                   next->next = list;
114                   record(todo, "Created entry %t previous was %t", next, list);
115                   list = next;
116                   crash += strcmp(argv[a], "crash") == 0;
117               }
118
119               while (list || crash)
120               {
121                   todo *next = list->next;
122                   record(todo, "Had item %t", list);
123                   free(list);
124                   list = next;
125               }
126           }
127
128
129       The following shows what happens if you run the program normally
130
131           % todo eat pray love
132
133
134       The  following  shows what happens if you trace the program: the struct
135       todo * values are formatted, showing additional information.
136
137           % RECORDER_TRACES=todo todo eat pray love
138           [34 0.000273] todo: Argument 1 is 'eat'
139           [35 0.000339] todo: Created entry todo@0x50ba80('eat') previous was (nil)
140           [36 0.000352] todo: Argument 2 is 'pray'
141           [37 0.000360] todo: Created entry todo@0x50ba60('pray') previous was todo@0x50ba80('eat')
142           [38 0.000368] todo: Argument 3 is 'love'
143           [39 0.000373] todo: Created entry todo@0x50ba40('love') previous was todo@0x50ba60('pray')
144           [40 0.000386] todo: Had item todo@0x50ba40('love')
145           [41 0.000394] todo: Had item todo@0x50ba60('pray')
146           [42 0.000477] todo: Had item todo@0x50ba80('eat')
147
148
149       The following shows what happens if the  program  crashes  due  to  bad
150       input:  the  crash  dump  no  longer  indicates the content of the todo
151       pointers, since it would be unsafe to dereference them at that time.
152
153
154           % todo crash and burn
155           [...]
156           [25 0.000052] recorders: Configure type 't' to 0x4011c6 from (nil)
157           [26 0.000067] todo: Argument 1 is 'crash'
158           [27 0.000146] todo: Created entry 0x1f9d260 previous was (nil)
159           [28 0.000150] todo: Argument 2 is 'and'
160           [29 0.000150] todo: Created entry 0x1f9d280 previous was 0x1f9d260
161           [30 0.000150] todo: Argument 3 is 'burn'
162           [31 0.000150] todo: Created entry 0x1f9d2a0 previous was 0x1f9d280
163           [32 0.000151] todo: Had item 0x1f9d2a0
164           [33 0.000152] todo: Had item 0x1f9d280
165           [34 0.000152] todo: Had item 0x1f9d260
166           [35 0.000172] signals: Received signal Segmentation fault (11) si_addr=0x8, dumping recorder
167           [36 0.000209] recorders: Recorder dump
168
169
170       Finally, the following shows what happens if you activate  tracing  and
171       the  program  crashes.  In that case, the tracing part at the top shows
172       the detailed information. However, during  the  crash  dump,  the  same
173       events  are replayed again (putting them in context with other events),
174       this time without dereferencing the pointer.
175
176
177           % RECORDER_TRACES=todo todo crash and burn
178           [...]
179           [34 0.000184] todo: Argument 1 is 'crash'
180           [35 0.000240] todo: Created entry todo@0xf6aa80('crash') previous was (nil)
181           [36 0.000250] todo: Argument 2 is 'and'
182           [37 0.000255] todo: Created entry todo@0xf6aa60('and') previous was todo@0xf6aa80('crash')
183           [38 0.000260] todo: Argument 3 is 'burn'
184           [39 0.000265] todo: Created entry todo@0xf6aa40('burn') previous was todo@0xf6aa60('and')
185           [40 0.000270] todo: Had item todo@0xf6aa40('burn')
186           [41 0.000275] todo: Had item todo@0xf6aa60('and')
187           [42 0.000279] todo: Had item todo@0xf6aa80('crash')
188           [...]
189           [33 0.000180] recorders: Configure type 't' to 0x4011c6 from (nil)
190           [34 0.000184] todo: Argument 1 is 'crash'
191           [35 0.000240] todo: Created entry 0xf6aa80 previous was (nil)
192           [36 0.000250] todo: Argument 2 is 'and'
193           [37 0.000255] todo: Created entry 0xf6aa60 previous was 0xf6aa80
194           [38 0.000260] todo: Argument 3 is 'burn'
195           [39 0.000265] todo: Created entry 0xf6aa40 previous was 0xf6aa60
196           [40 0.000270] todo: Had item 0xf6aa40
197           [41 0.000275] todo: Had item 0xf6aa60
198           [42 0.000279] todo: Had item 0xf6aa80
199           [43 0.000297] signals: Received signal Segmentation fault (11) si_addr=0x8, dumping recorder
200           [44 0.000309] recorders: Recorder dump
201
202
203

BUGS

205       Using this function will render your format strings wildly incompatible
206       with  the  standard  printf(3)  format,  possibly making your code less
207       readable.
208
209
210       There is a very limited number of possible type identifiers. Using this
211       feature  in  a  shared library may cause conflicts with other code that
212       would also want to override the same format character.
213
214
215       It is possible to override standard format characters using this  func‐
216       tion. Whether this is a bug or a feature remains to be seen.
217
218
219       Bugs should be reported using https://github.com/c3d/recorder/issues.
220
221
222

SEE ALSO

224       RECORDER_DEFINE(3), RECORDER_DECLARE(3)
225       recorder_trace_set(3) RECORDER_TRACE(3)
226       recorder_dump(3), recorder_dump_for(3),
227       recorder_configure_output(3), recorder_configure_show(3)
228       recorder_configure_format(3), recorder_configure_type(3)
229
230
231       Additional    documentation    and    tutorials   can   be   found   at
232       https://github.com/c3d/recorder.
233
234
235

AUTHOR

237       Written by Christophe de Dinechin
238
239
240
2411.0                               2019-03-09        recorder_configure_type(3)
Impressum