Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
nix/afw_os.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework OS Specific Functions for *nix systems
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
14 #include "afw.h"
15 #include <sys/types.h>
16 #include <sys/utsname.h>
17 #include <sys/time.h>
18 #include <sys/resource.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <execinfo.h>
22 
23 #ifndef __MACH__
24 #define UNW_LOCAL_ONLY
25 #include <libunwind.h>
26 #include <elfutils/libdwfl.h>
27 #endif
28 
29 static const afw_utf8_t impl_s_no_memory_for_backtrace =
30  AFW_UTF8_LITERAL("No memory for backtrace");
31 
32 static const afw_utf8_t impl_dso_suffix =
33  AFW_UTF8_LITERAL(".so");
34 
35 static const afw_utf8_t impl_s_general_description =
36  AFW_UTF8_LITERAL("General systems info.");
37 
38 /* string definitions for the system uname() function */
39 static const afw_utf8_t impl_s_sysname =
40 AFW_UTF8_LITERAL("sysname");
41 
42 static const afw_utf8_t impl_s_nodename =
43 AFW_UTF8_LITERAL("nodename");
44 
45 static const afw_utf8_t impl_s_release =
46 AFW_UTF8_LITERAL("release");
47 
48 static const afw_utf8_t impl_s_version =
49 AFW_UTF8_LITERAL("version");
50 
51 static const afw_utf8_t impl_s_machine =
52 AFW_UTF8_LITERAL("machine");
53 
54 static const afw_utf8_t impl_s_domainname =
55 AFW_UTF8_LITERAL("domainname");
56 
57 
58 /* string literals for resource usage object */
59 static const afw_utf8_t impl_s_resourceUsage =
60 AFW_UTF8_LITERAL("resourceUsage");
61 
62 static const afw_utf8_t impl_s_ru_utime =
63 AFW_UTF8_LITERAL("utime");
64 
65 static const afw_utf8_t impl_s_ru_stime =
66 AFW_UTF8_LITERAL("stime");
67 
68 static const afw_utf8_t impl_s_ru_maxrss =
69 AFW_UTF8_LITERAL("maxrss");
70 
71 static const afw_utf8_t impl_s_ru_ixrss =
72 AFW_UTF8_LITERAL("ixrss");
73 
74 static const afw_utf8_t impl_s_ru_idrss =
75 AFW_UTF8_LITERAL("idrss");
76 
77 static const afw_utf8_t impl_s_ru_isrss =
78 AFW_UTF8_LITERAL("isrss");
79 
80 static const afw_utf8_t impl_s_ru_minflt =
81 AFW_UTF8_LITERAL("minflt");
82 
83 static const afw_utf8_t impl_s_ru_majflt =
84 AFW_UTF8_LITERAL("majflt");
85 
86 static const afw_utf8_t impl_s_ru_nswap =
87 AFW_UTF8_LITERAL("nswap");
88 
89 static const afw_utf8_t impl_s_ru_inblock =
90 AFW_UTF8_LITERAL("inblock");
91 
92 static const afw_utf8_t impl_s_ru_oublock =
93 AFW_UTF8_LITERAL("oublock");
94 
95 static const afw_utf8_t impl_s_ru_msgsnd =
96 AFW_UTF8_LITERAL("msgsnd");
97 
98 static const afw_utf8_t impl_s_ru_msgrcv =
99 AFW_UTF8_LITERAL("msgrcv");
100 
101 static const afw_utf8_t impl_s_ru_nsignals =
102 AFW_UTF8_LITERAL("nsignals");
103 
104 static const afw_utf8_t impl_s_ru_nvcsw =
105 AFW_UTF8_LITERAL("nvcsw");
106 
107 static const afw_utf8_t impl_s_ru_nivcsw =
108 AFW_UTF8_LITERAL("nivcsw");
109 
110 /* string literals for resource usage object */
111 static const afw_utf8_t impl_s_resourceLimits =
112 AFW_UTF8_LITERAL("resourceLimits");
113 
114 static const afw_utf8_t impl_s_rl_cpu =
115 AFW_UTF8_LITERAL("cpu");
116 
117 static const afw_utf8_t impl_s_rl_fsize =
118 AFW_UTF8_LITERAL("fsize");
119 
120 static const afw_utf8_t impl_s_rl_stack =
121 AFW_UTF8_LITERAL("stack");
122 
123 static const afw_utf8_t impl_s_rl_core =
124 AFW_UTF8_LITERAL("core");
125 
126 static const afw_utf8_t impl_s_rl_rss =
127 AFW_UTF8_LITERAL("rss");
128 
129 static const afw_utf8_t impl_s_rl_memlock =
130 AFW_UTF8_LITERAL("memlock");
131 
132 static const afw_utf8_t impl_s_rl_nproc =
133 AFW_UTF8_LITERAL("nproc");
134 
135 static const afw_utf8_t impl_s_rl_ofile =
136 AFW_UTF8_LITERAL("ofile");
137 
138 static const afw_utf8_t impl_s_rl_as =
139 AFW_UTF8_LITERAL("as");
140 
141 
142 #ifdef __EXAMPLE_FOR_CREATING_WITH_CB_WRAPPER_
143 
144 static const afw_utf8_t
145 impl_s_<objectId>_description =
146  AFW_UTF8_LITERAL("FIXME");
147 
148 static const afw_utf8_t
149 impl_s_os =
150 AFW_UTF8_LITERAL("os");
151 
152 static const afw_utf8_t
153 impl_s_os_label =
154 AFW_UTF8_LITERAL("OS");
155 
156 static const afw_utf8_t
157 impl_s_os_description =
158 AFW_UTF8_LITERAL("Operating system.");
159 
160 static const afw_utf8_t
161 impl_s_linux =
162 AFW_UTF8_LITERAL("linux");
163 
164 static const afw_object_t *
165 impl_get_<objectId>_object_cb(
166  void *data,
167  const afw_pool_t *p,
168  afw_xctx_t *xctx)
169 {
170  const afw_object_t *result;
171 
172  /* Construct system specific object. */
173  result = afw_object_create(p, xctx);
175  &afw_s_afw,
176  &afw_s__AdaptiveSystemInfo_,
177  &afw_s_<objectId>,
178  xctx);
179  afw_object_meta_set_property_as(result, &afw_s_description,
180  string, &impl_s_<objectId>_description, xctx);
181  afw_object_meta_set_read_only(result, xctx);
182 
183  /* Add in system specific info properties. */
186  &impl_s_os, &impl_s_linux, xctx);
188  &impl_s_os, &afw_s_label,
189  single, string, &impl_s_os_label, xctx);
191  &impl_s_os, &afw_s_description,
192  single, string, &impl_s_os_description, xctx);
193 
194  /* Return result. */
195  return result;
196 }
197 
198 #endif /* __EXAMPLE_FOR_CREATING_WITH_CB_WRAPPER_ */
199 
200 static const afw_object_t *
201 impl_get_resourceLimits_object_cb(
202  void *data,
203  const afw_pool_t *p,
204  afw_xctx_t *xctx)
205 {
206  const afw_object_t *result;
207  struct rlimit *limits;
208  int rc;
209 
210  /* Construct system specific object. */
211  result = afw_object_create(p, xctx);
213  &afw_s_afw,
214  &afw_s__AdaptiveSystemInfo_,
215  &impl_s_resourceLimits,
216  xctx);
217 
219  result, &afw_s_description,
220  "Resource Limits for the calling process.",
221  xctx);
222  afw_object_meta_set_read_only(result, xctx);
223 
224  limits = afw_pool_calloc_type(p, struct rlimit, xctx);
225 
226  rc = getrlimit(RLIMIT_CPU, limits);
227  if (rc == 0) {
229  &impl_s_rl_cpu, limits->rlim_cur, xctx);
231  &impl_s_rl_cpu, &afw_s_label, "CPU Time", xctx);
233  &impl_s_rl_cpu, &afw_s_description,
234  "The maximum amount of CPU time the process can use. If it runs for longer than this, it gets a signal: SIGXCPU. The value is measured in seconds.",
235  xctx);
236  }
237 
238  rc = getrlimit(RLIMIT_FSIZE, limits);
239  if (rc == 0) {
241  &impl_s_rl_fsize, limits->rlim_cur, xctx);
243  &impl_s_rl_fsize, &afw_s_label, "File Size", xctx);
245  &impl_s_rl_fsize, &afw_s_description,
246  "The maximum size of file the process can create. Trying to write a larger file causes a signal: SIGXFSZ.",
247  xctx);
248  }
249 
250  rc = getrlimit(RLIMIT_STACK, limits);
251  if (rc == 0) {
253  &impl_s_rl_stack, limits->rlim_cur, xctx);
255  &impl_s_rl_stack, &afw_s_label, "Stack Size", xctx);
257  &impl_s_rl_stack, &afw_s_description,
258  "The maximum stack size for the process. If the process tries to extend its stack past this size, it gets a SIGSEGV signal",
259  xctx);
260  }
261 
262  rc = getrlimit(RLIMIT_CORE, limits);
263  if (rc == 0) {
265  &impl_s_rl_core, limits->rlim_cur, xctx);
267  &impl_s_rl_core, &afw_s_label, "Core Size", xctx);
269  &impl_s_rl_core, &afw_s_description,
270  "The maximum size core file that this process can create. If the process terminates and would dump a core file larger than this, then no core file is created. So setting this limit to zero prevents core files from ever being created.",
271  xctx);
272  }
273 
274  rc = getrlimit(RLIMIT_RSS, limits);
275  if (rc == 0) {
277  &impl_s_rl_rss, limits->rlim_cur, xctx);
279  &impl_s_rl_rss, &afw_s_label, "Physical Memory", xctx);
281  &impl_s_rl_rss, &afw_s_description,
282  "The maximum amount of physical memory that this process should get. This parameter is a guide for the system’s scheduler and memory allocator; the system may give the process more memory when there is a surplus.",
283  xctx);
284  }
285 
286  rc = getrlimit(RLIMIT_MEMLOCK, limits);
287  if (rc == 0) {
289  &impl_s_rl_memlock, limits->rlim_cur, xctx);
291  &impl_s_rl_memlock, &afw_s_label, "Locked Physical Memory", xctx);
293  &impl_s_rl_memlock, &afw_s_description,
294  "The maximum amount of memory that can be locked into physical memory (so it will never be paged out).",
295  xctx);
296  }
297 
298  rc = getrlimit(RLIMIT_NPROC, limits);
299  if (rc == 0) {
301  &impl_s_rl_nproc, limits->rlim_cur, xctx);
303  &impl_s_rl_nproc, &afw_s_label, "Processes", xctx);
305  &impl_s_rl_nproc, &afw_s_description,
306  "The maximum number of processes that can be created with the same user ID. If you have reached the limit for your user ID, fork will fail with EAGAIN.",
307  xctx);
308  }
309 
310 #if defined(RLIMIT_NOFILE)
311  rc = getrlimit(RLIMIT_NOFILE, limits);
312 #else
313  rc = getrlimit(RLIMIT_OFILE, limits);
314 #endif
315  if (rc == 0) {
317  &impl_s_rl_ofile, limits->rlim_cur, xctx);
319  &impl_s_rl_ofile, &afw_s_label, "Open Files", xctx);
321  &impl_s_rl_ofile, &afw_s_description,
322  "The maximum number of files that the process can open. If it tries to open more files than this, its open attempt fails with errno EMFILE.",
323  xctx);
324  }
325 
326 #ifdef __MACH__
327  rc = getrlimit(RLIMIT_DATA, limits);
328 #else
329  rc = getrlimit(RLIMIT_AS, limits);
330 #endif
331  if (rc == 0) {
333  &impl_s_rl_as, limits->rlim_cur, xctx);
335  &impl_s_rl_as, &afw_s_label, "Total Memory", xctx);
337  &impl_s_rl_as, &afw_s_description,
338  "The maximum size of total memory that this process should get. If the process tries to allocate more memory beyond this amount with, for example, brk, malloc, mmap or sbrk, the allocation function fails.",
339  xctx);
340  }
341 
342  return result;
343 }
344 
345 static const afw_object_t *
346 impl_get_resourceUsage_object_cb(
347  void *data,
348  const afw_pool_t *p,
349  afw_xctx_t *xctx)
350 {
351  const afw_object_t *result;
352  struct rusage *usage;
353  int rc;
354 
355  /* Construct system specific object. */
356  result = afw_object_create(p, xctx);
358  &afw_s_afw,
359  &afw_s__AdaptiveSystemInfo_,
360  &impl_s_resourceUsage,
361  xctx);
362 
364  result, &afw_s_description,
365  "Resource usage statistics for the calling process, which is the sum of resources used by all threads in the process.",
366  xctx);
367  afw_object_meta_set_read_only(result, xctx);
368 
369  usage = afw_pool_calloc_type(p, struct rusage, xctx);
370  rc = getrusage(RUSAGE_SELF, usage);
371  if (rc == 0) {
373  &impl_s_ru_utime, true,
374  0, 0, 0, usage->ru_utime.tv_sec, usage->ru_utime.tv_usec,
375  xctx);
377  &impl_s_ru_utime, &afw_s_label, "User Time", xctx);
379  &impl_s_ru_utime, &afw_s_description,
380  "Time spent executing user instructions.",
381  xctx);
382 
384  &impl_s_ru_stime, true,
385  0, 0, 0, usage->ru_stime.tv_sec, usage->ru_stime.tv_usec,
386  xctx);
388  &impl_s_ru_stime, &afw_s_label, "System Time", xctx);
390  &impl_s_ru_stime, &afw_s_description,
391  "Time spent in operating system code on behalf of this processes.",
392  xctx);
393 
395  &impl_s_ru_maxrss, usage->ru_maxrss, xctx);
397  &impl_s_ru_maxrss, &afw_s_label, "Max Resident Size", xctx);
399  &impl_s_ru_maxrss, &afw_s_description,
400  "The maximum resident set size used, in kilobytes. That is, the maximum number of kilobytes of physical memory that this process used simultaneously.",
401  xctx);
402 
404  &impl_s_ru_ixrss, usage->ru_ixrss, xctx);
406  &impl_s_ru_ixrss, &afw_s_label, "Shared Memory Size", xctx);
408  &impl_s_ru_ixrss, &afw_s_description,
409  "An integral value expressed in kilobytes times ticks of execution, which indicates the amount of memory used by text that was shared with other processes.",
410  xctx);
411 
413  &impl_s_ru_idrss, usage->ru_idrss, xctx);
415  &impl_s_ru_idrss, &afw_s_label, "Unshared Data Size", xctx);
417  &impl_s_ru_idrss, &afw_s_description,
418  "An integral value expressed the same way, which is the amount of unshared memory used for data.",
419  xctx);
420 
422  &impl_s_ru_isrss, usage->ru_isrss, xctx);
424  &impl_s_ru_isrss, &afw_s_label, "Unshared Stack Size", xctx);
426  &impl_s_ru_isrss, &afw_s_description,
427  "An integral value expressed the same way, which is the amount of unshared memory used for stack space.",
428  xctx);
429 
431  &impl_s_ru_minflt, usage->ru_minflt, xctx);
433  &impl_s_ru_minflt, &afw_s_label, "Page Reclaims", xctx);
435  &impl_s_ru_minflt, &afw_s_description,
436  "The number of page faults which were serviced without requiring any I/O.",
437  xctx);
438 
440  &impl_s_ru_majflt, usage->ru_majflt, xctx);
442  &impl_s_ru_majflt, &afw_s_label, "Page Faults", xctx);
444  &impl_s_ru_majflt, &afw_s_description,
445  "The number of page faults which were serviced by doing I/O.",
446  xctx);
447 
449  &impl_s_ru_nswap, usage->ru_nswap, xctx);
451  &impl_s_ru_nswap, &afw_s_label, "Swaps", xctx);
453  &impl_s_ru_nswap, &afw_s_description,
454  "The number of times this processes was swapped entirely out of main memory.",
455  xctx);
456 
458  &impl_s_ru_inblock, usage->ru_inblock, xctx);
460  &impl_s_ru_inblock, &afw_s_label, "Disk Reads", xctx);
462  &impl_s_ru_inblock, &afw_s_description,
463  "The number of times the file system had to read from the disk on behalf of this processes.",
464  xctx);
465 
467  &impl_s_ru_oublock, usage->ru_oublock, xctx);
469  &impl_s_ru_oublock, &afw_s_label, "Disk Writes", xctx);
471  &impl_s_ru_oublock, &afw_s_description,
472  "The number of times the file system had to write to the disk on behalf of this processes.",
473  xctx);
474 
476  &impl_s_ru_msgsnd, usage->ru_msgsnd, xctx);
478  &impl_s_ru_msgsnd, &afw_s_label, "Messages Sent", xctx);
480  &impl_s_ru_msgsnd, &afw_s_description,
481  "Number of IPC messages sent.",
482  xctx);
483 
485  &impl_s_ru_msgrcv, usage->ru_msgrcv, xctx);
487  &impl_s_ru_msgrcv, &afw_s_label, "Messages Received", xctx);
489  &impl_s_ru_msgrcv, &afw_s_description,
490  "Number of IPC messages received.",
491  xctx);
492 
494  &impl_s_ru_nsignals, usage->ru_nsignals, xctx);
496  &impl_s_ru_nsignals, &afw_s_label, "Signals Received", xctx);
498  &impl_s_ru_nsignals, &afw_s_description,
499  "Number of signals received.",
500  xctx);
501 
503  &impl_s_ru_nvcsw, usage->ru_nvcsw, xctx);
505  &impl_s_ru_nvcsw, &afw_s_label, "Voluntary Context Switches", xctx);
507  &impl_s_ru_nvcsw, &afw_s_description,
508  "The number of times this processes voluntarily invoked a context switch (usually to wait for some service).",
509  xctx);
510 
512  &impl_s_ru_nivcsw, usage->ru_nivcsw, xctx);
514  &impl_s_ru_nivcsw, &afw_s_label, "Involuntary Context Switches", xctx);
516  &impl_s_ru_nivcsw, &afw_s_description,
517  "The number of times an involuntary context switch took place (because a time slice expired, or another process of higher priority was scheduled).",
518  xctx);
519  }
520 
521  /* Return result. */
522  return result;
523 }
524 
525 /* Create /afw/_AdaptiveSystemInfo_/general object. */
526 static const afw_object_t *
527 impl_create_general_object(afw_xctx_t *xctx)
528 {
529  const afw_object_t *result;
530  struct utsname *uname_s;
531  int rc;
532 
533  /* Construct system specific object. */
534  result = afw_object_create(xctx->p, xctx);
536  &afw_s_afw,
537  &afw_s__AdaptiveSystemInfo_,
538  &afw_s_general,
539  xctx);
540  afw_object_meta_set_property_as(result, &afw_s_description,
541  string, &impl_s_general_description, xctx);
542  afw_object_meta_set_read_only(result, xctx);
543 
544  /* use uname() to gather system name information */
545  uname_s = afw_xctx_calloc_type(struct utsname, xctx);
546  rc = uname(uname_s);
547  if (rc > -1) {
549  &impl_s_sysname, uname_s->sysname, xctx);
551  &impl_s_sysname, &afw_s_label, "System Name", xctx);
553  &impl_s_sysname, &afw_s_description, "This is the name of the operating system in use.", xctx);
554 
556  &impl_s_nodename, uname_s->nodename, xctx);
558  &impl_s_nodename, &afw_s_label, "Node Name", xctx);
560  &impl_s_nodename, &afw_s_description, "This is the host name of this particular computer. In the GNU C Library, the value is the same as that returned by gethostname.", xctx);
561 
563  &impl_s_release, uname_s->release, xctx);
565  &impl_s_release, &afw_s_label, "Release", xctx);
567  &impl_s_release, &afw_s_description, "This is the current release level of the operating system implementation.", xctx);
568 
570  &impl_s_version, uname_s->version, xctx);
572  &impl_s_version, &afw_s_label, "Version", xctx);
574  &impl_s_version, &afw_s_description, "This is the current version level within the release of the operating system.", xctx);
575 
577  &impl_s_machine, uname_s->machine, xctx);
579  &impl_s_machine, &afw_s_label, "Machine", xctx);
581  &impl_s_machine, &afw_s_description, "This is a description of the type of hardware that is in use.", xctx);
582 
583 #ifndef __MACH__
593  &impl_s_domainname, &afw_s_label, "Domain Name", xctx);
595  &impl_s_domainname, &afw_s_description, "This is the NIS or YP domain name. It is the same value returned by getdomainname.", xctx);
596 #endif
597  }
598 
599  /* Return result. */
600  return result;
601 }
602 
603 
604 
605 /* afw_os environment initialize */
606 AFW_DEFINE(void)
608 {
609  const afw_log_factory_t *log_factory;
610  const afw_object_t *object;
611 
612  /* Register factory for os log. */
613  log_factory = afw_os_log_factory_get();
615  &log_factory->log_type,
616  log_factory, xctx);
617 
618  /* Create and set general object. */
619  object = impl_create_general_object(xctx);
620  afw_runtime_env_set_object(object, false, xctx);
621 
622  /* Set resourceUsage object wrapper. */
624  &afw_s__AdaptiveSystemInfo_, &impl_s_resourceUsage,
625  impl_get_resourceUsage_object_cb, NULL, false, xctx);
626 
627  /* Set resourceLimits object wrapper. */
629  &afw_s__AdaptiveSystemInfo_, &impl_s_resourceLimits,
630  impl_get_resourceLimits_object_cb, NULL, false, xctx);
631 }
632 
633 
634 /* Return a process id or similar number. */
636 {
637  return getpid();
638 }
639 
640 
641 /* Return the suffix appended to dso file names for this system. */
642 AFW_DEFINE(const afw_utf8_t *)
644 {
645  return &impl_dso_suffix;
646 }
647 
648 
649 /*
650  * Provide a backtrace if possible. This routine
651  * relies on libunwind to capture the stack frames
652  * and libdw (from ELF utilities) to resolve debug
653  * info such as file names and line numbers.
654  *
655  * There are a few caveats here:
656  * 1. Symbols are needed, so the binary needs to be
657  * compiled with the -g option.
658  * 2. Unpredictable results may happen when compiler
659  * optimizations are turned on.
660  */
661 #ifdef __MACH__
662 AFW_DEFINE(const afw_utf8_t *)
664  afw_error_code_t code,
665  int max_backtrace,
666  afw_xctx_t *xctx)
667 {
668  void * callstack[128];
669  int i, max;
670  int frames;
671  char ** strs;
672  afw_byte_t *s;
673  afw_size_t len;
674  afw_utf8_t *trace = NULL;
675  int wlen;
676 
677  /*
678  * If max_backtrace is -1 or greater than 99, cap at 99. If 0, NULL will
679  * be returned.
680  *
681  * Variable max is one more to avoid the trace of call to this function.
682  */
683  if (max_backtrace == 0) return NULL;
684  if (max_backtrace < 0) max = 100;
685  else if (max_backtrace > 99) max = 100;
686  else max = max_backtrace + 1;
687 
688  /*
689  * Allocate and initialize memory to hold result.
690  *
691  * Variable len is an approximation of the buffer needed to build the
692  * result. if it is not large enough, the the trace returned will be
693  * truncated to what will fit. The average line size is assumed to
694  * be 100 plus 10 extra lines for other error info.
695  */
696  len = (max + 10) * 100;
697  s = apr_palloc(afw_pool_get_apr_pool(xctx->p), len);
698  if (!s) return &impl_s_no_memory_for_backtrace;
699  trace = apr_palloc(afw_pool_get_apr_pool(xctx->p), sizeof(afw_utf8_t));
700  if (!trace) return &impl_s_no_memory_for_backtrace;
701  trace->s = s;
702  *s++ = '\n';
703  len--;
704 
705  frames = backtrace(callstack, 128);
706  if (!frames)
707  return NULL;
708 
709  strs = backtrace_symbols(callstack, frames);
710  if (!strs)
711  return NULL;
712 
713  for (i = 0; i < frames; i++) {
714  wlen = snprintf(s, len, "%s\n", strs[i]);
715  if (wlen < 0 || (afw_size_t)wlen > len) break;
716  s += wlen;
717  len -= wlen;
718  }
719 
720  free(strs);
721 
722  trace->len = s - trace->s;
723 
724  return trace;
725 }
726 
727 #else
728 AFW_DEFINE(const afw_utf8_t *)
730  afw_error_code_t code,
731  int max_backtrace,
732  afw_xctx_t *xctx)
733 {
734  char *debuginfo_path = NULL;
735  Dwfl_Callbacks callbacks = {
736  .find_elf = dwfl_linux_proc_find_elf,
737  .find_debuginfo = dwfl_standard_find_debuginfo,
738  .debuginfo_path = &debuginfo_path,
739  };
740  Dwfl *dwfl;
741  Dwarf_Addr addr;
742  Dwfl_Module *module;
743  Dwfl_Line *line;
744  const afw_utf8_octet_t *function_name;
745  unw_cursor_t cursor;
746  unw_context_t uc;
747  int i, max;
748  int rc;
749 
750  afw_utf8_octet_t *s;
751  afw_size_t len;
752  afw_utf8_t *trace = NULL;
753  int wlen;
754 
755  /*
756  * If max_backtrace is -1 or greater than 99, cap at 99. If 0, NULL will
757  * be returned.
758  *
759  * Variable max is one more to avoid the trace of call to this function.
760  */
761  if (max_backtrace == 0) return NULL;
762  if (max_backtrace < 0) max = 100;
763  else if (max_backtrace > 99) max = 100;
764  else max = max_backtrace + 1;
765 
766  /*
767  * Allocate and initialize memory to hold result.
768  *
769  * Variable len is an approximation of the buffer needed to build the
770  * result. if it is not large enough, the the trace returned will be
771  * truncated to what will fit. The average line size is assumed to
772  * be 100 plus 10 extra lines for other error info.
773  */
774  len = (max + 10) * 100;
775  s = apr_palloc(afw_pool_get_apr_pool(xctx->p), len);
776  if (!s) return &impl_s_no_memory_for_backtrace;
777  trace = apr_palloc(afw_pool_get_apr_pool(xctx->p), sizeof(afw_utf8_t));
778  if (!trace) return &impl_s_no_memory_for_backtrace;
779  trace->s = s;
780  *s++ = '\n';
781  len--;
782 
783  dwfl = dwfl_begin(&callbacks);
784  if (!dwfl) {
785  return &impl_s_no_memory_for_backtrace;
786  }
787 
788  dwfl_linux_proc_report(dwfl, getpid());
789  dwfl_report_end(dwfl, NULL, NULL);
790 
791  unw_getcontext(&uc);
792  rc = unw_init_local(&cursor, &uc);
793  if (rc) {
794  /* error occurred, initializing cursor for local unwinding */
795  dwfl_end(dwfl);
796  return trace;
797  }
798 
799  for (i = 0; unw_step(&cursor) > 0 && i < max; i++) {
800  unw_word_t offset, ip, sp;
801  char sym[256];
802 
803  unw_get_reg(&cursor, UNW_REG_IP, &ip);
804  unw_get_reg(&cursor, UNW_REG_SP, &sp);
805  if (ip == 0) {
806  break;
807  }
808 
809  wlen = snprintf(s, len, "0x%012lx in ", ip);
810  if (wlen < 0 || (afw_size_t)wlen > len) break;
811  s += wlen;
812  len -= wlen;
813 
814  addr = (uintptr_t)(ip-4);
815  module = dwfl_addrmodule(dwfl, addr);
816  function_name = dwfl_module_addrname(module, addr);
817  line = dwfl_getsrc(dwfl, addr);
818  if (line != NULL) {
819  int nline;
820  Dwarf_Addr addr;
821  const char *filename = dwfl_lineinfo(line, &addr, &nline, NULL, NULL, NULL);
822 
823  wlen = snprintf(s, len, "%s at %s:%d\n",
824  function_name, strrchr(filename, '/') + 1, nline);
825  if (wlen < 0 || (afw_size_t)wlen > len) break;
826  s += wlen;
827  len -= wlen;
828  } else {
829  if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
830  wlen = snprintf(s, len, "%s at +0x%lx\n",
831  sym, offset);
832  if (wlen < 0 || (afw_size_t)wlen > len) break;
833  s += wlen;
834  len -= wlen;
835  } else {
836  wlen = snprintf(s, len, "(symbol missing)\n");
837  if (wlen < 0 || (afw_size_t)wlen > len) break;
838  s += wlen;
839  len -= wlen;
840  }
841  }
842  }
843 
844  trace->len = s - trace->s;
845 
846  /* free resources from dwfl_begin */
847  dwfl_end(dwfl);
848 
849  return trace;
850 }
851 #endif
Adaptive Framework Core API.
AFW_DEFINE(const afw_object_t *)
afw_object_set_property_as_integer(const afw_object_t *object, const afw_utf8_t *property_name, afw_integer_t internal, afw_xctx_t *xctx)
Set property function for data type integer values.
afw_object_set_property_as_string(const afw_object_t *object, const afw_utf8_t *property_name, const afw_utf8_t *internal, afw_xctx_t *xctx)
Set property function for data type string values.
#define AFW_UTF8_LITERAL(A_STRING)
String literal initializer.
Definition: afw_common.h:582
enum afw_error_code_e afw_error_code_t
unsigned char afw_byte_t
A byte of memory (unsigned).
Definition: afw_common.h:208
apr_uint32_t afw_uint32_t
32-bit unsigned integer.
Definition: afw_common.h:184
char afw_utf8_octet_t
8 bits of utf-8 codepoint.
Definition: afw_common.h:236
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
void afw_environment_register_log_type(const afw_utf8_t *log_type, const afw_log_factory_t *log_factory, afw_xctx_t *xctx)
Register an log factory.
#define afw_object_meta_set_property_from_utf8_z(instance, property_name, string_z, xctx)
Set a string property in the meta of an object from utf8_z.
#define afw_object_meta_set_property_type_property_as(instance, property_name, property_type_property_name, data_type, value, xctx)
Set a property type property for a property in the meta of an object as a value and data type.
afw_object_meta_set_read_only(const afw_object_t *instance, afw_xctx_t *xctx)
Set object's meta to indicate object is read-only.
#define afw_object_meta_set_property_as(instance, property_name, data_type, value, xctx)
Set a property in the meta of an object as a value and data type.
#define afw_object_meta_set_property_type_property_from_utf8_z(instance, property_name, property_type_property_name, string_z, xctx)
Set a property type string property for a property in the meta of an object from utf8_z.
afw_object_meta_set_ids(const afw_object_t *instance, const afw_utf8_t *adaptor_id, const afw_utf8_t *object_type_id, const afw_utf8_t *object_id, afw_xctx_t *xctx)
Set object's ids.
afw_object_set_property_as_dayTimeDuration_from_parts(const afw_object_t *instance, const afw_utf8_t *property_name, afw_boolean_t is_positive, int days, int hours, int minutes, int seconds, int microseconds, afw_xctx_t *xctx)
Set a dayTimeDuration property from parts.
Definition: afw_object.c:121
#define afw_object_create(p, xctx)
Create an empty unmanaged object in memory.
Definition: afw_object.h:948
afw_object_set_property_as_string_from_utf8_z(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_utf8_z_t *string_z, afw_xctx_t *xctx)
Set an string property from utf8_z.
Definition: afw_object.c:194
afw_os_environment_initialize(afw_xctx_t *xctx)
afw_os environment initialize
Definition: nix/afw_os.c:607
afw_os_backtrace(afw_error_code_t code, int max_backtrace, afw_xctx_t *xctx)
Provide a backtrace if possible.
Definition: nix/afw_os.c:729
afw_os_get_dso_suffix()
Return the suffix appended to dso file names for this system.
Definition: nix/afw_os.c:643
afw_uint32_t afw_os_get_pid()
Return a process id or similar number.
Definition: win/afw_os.c:174
const afw_log_factory_t * afw_os_log_factory_get()
Get the factory for OS log.
#define afw_pool_get_apr_pool(instance)
Call method get_apr_pool of interface afw_pool.
#define afw_pool_calloc_type(instance, type, xctx)
Macro to allocate cleared memory to hold type in pool.
Definition: afw_pool.h:167
afw_runtime_env_set_object(const afw_object_t *object, afw_boolean_t overwrite, afw_xctx_t *xctx)
Set an object pointer in the environment's runtime objects.
Definition: afw_runtime.c:210
afw_runtime_env_set_object_cb_wrapper(const afw_utf8_t *object_type_id, const afw_utf8_t *object_id, afw_runtime_object_wrapper_p_cb_t callback, void *data, afw_boolean_t overwrite, afw_xctx_t *xctx)
Set environment object accessed via callback.
Definition: afw_runtime.c:240
#define afw_xctx_calloc_type(type, xctx)
Macro to allocate cleared memory to hold type in xctx's pool.
Definition: afw_xctx.h:199
Interface afw_log_factory public struct.
Interface afw_object public struct.
Interface afw_pool public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Interface afw_xctx public struct.