LCOV - code coverage report
Current view: top level - AP_HAL_SITL - system.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 20 104 19.2 %
Date: 2026-09-09 11:02:08 Functions: 6 10 60.0 %

          Line data    Source code
       1             : #include <stdarg.h>
       2             : #include <errno.h>
       3             : #include <limits.h>
       4             : #include <stdio.h>
       5             : #include <sys/stat.h>
       6             : #include <sys/types.h>
       7             : #include <unistd.h>
       8             : #include <fcntl.h>
       9             : 
      10             : #include <AP_HAL/AP_HAL.h>
      11             : #include <AP_HAL/system.h>
      12             : 
      13             : #include "Scheduler.h"
      14             : #include <AP_Math/div1000.h>
      15             : 
      16             : extern const AP_HAL::HAL& hal;
      17             : 
      18             : using HALSITL::Scheduler;
      19             : 
      20             : namespace AP_HAL {
      21             : 
      22             : static struct {
      23             :     uint64_t start_time_ns;
      24             : } state;
      25             : 
      26        2247 : static uint64_t ts_to_nsec(struct timespec &ts)
      27             : {
      28        2247 :     return ts.tv_sec*1000000000ULL + ts.tv_nsec;
      29             : }
      30             :     
      31        2145 : void init()
      32             : {
      33        2145 :     struct timespec ts {};
      34        2145 :     clock_gettime(CLOCK_MONOTONIC, &ts);
      35        2145 :     state.start_time_ns = ts_to_nsec(ts);
      36        2145 : }
      37             : 
      38           0 : void WEAK panic(const char *errormsg, ...)
      39             : {
      40             :     va_list ap;
      41             : 
      42           0 :     fflush(stdout);
      43           0 :     printf("PANIC: ");
      44           0 :     va_start(ap, errormsg);
      45           0 :     vprintf(errormsg, ap);
      46           0 :     va_end(ap);
      47           0 :     printf("\n");
      48             : 
      49           0 :     dump_stack_trace();
      50           0 :     dump_core_file();
      51             : 
      52           0 :     if (getenv("SITL_PANIC_EXIT")) {
      53             :         // this is used on the autotest server to prevent us waiting
      54             :         // 10 hours for a timeout
      55           0 :         printf("panic and SITL_PANIC_EXIT set - exitting");
      56           0 :         exit(1);
      57             :     }
      58           0 :     for(;;);
      59             : }
      60             : 
      61             : // partly flogged from: https://github.com/tridge/junkcode/blob/master/segv_handler/segv_handler.c
      62           0 : static void run_command_on_ownpid(const char *commandname)
      63             : {
      64             :     // find dumpstack command:
      65           0 :     const char *command_filepath = commandname; // if we can't find it trust in PATH
      66             :     struct stat statbuf;
      67           0 :     const char *custom_scripts_dir_path = getenv("AP_SCRIPTS_DIR_PATH");
      68           0 :     char *custom_scripts_dir_path_pattern = nullptr;
      69           0 :     if (custom_scripts_dir_path != nullptr) {
      70           0 :         if (asprintf(&custom_scripts_dir_path_pattern, "%s/%%s", custom_scripts_dir_path) == -1) {
      71           0 :             custom_scripts_dir_path_pattern = nullptr;
      72             :         }
      73             :     }
      74           0 :     const char *paths[] {
      75             :         custom_scripts_dir_path_pattern,
      76             :         "Tools/scripts/%s",
      77             :         "APM/Tools/scripts/%s", // for autotest server
      78             :         "../Tools/scripts/%s", // when run from e.g. ArduCopter subdirectory
      79           0 :     };
      80             :     // long enough for an absolute path from AP_SCRIPTS_DIR_PATH; the 60
      81             :     // bytes this used to be was not - a checkout under a path of any
      82             :     // length silently truncated, and the truncated name simply failed to
      83             :     // stat, so the override looked as though it had been ignored
      84             :     char buffer[PATH_MAX];
      85           0 :     for (uint8_t i=0; i<ARRAY_SIZE(paths); i++) {
      86           0 :         if (paths[i] == nullptr) {
      87           0 :             continue;
      88             :         }
      89             :         // form up a filepath from each path and commandname; if it
      90             :         // exists, use it
      91           0 :         const int len = snprintf(buffer, sizeof(buffer), paths[i], commandname);
      92           0 :         if (len < 0 || (unsigned)len >= sizeof(buffer)) {
      93             :             // truncated, so this is not the path we were asked for
      94           0 :             continue;
      95             :         }
      96           0 :         if (::stat(buffer, &statbuf) != -1) {
      97           0 :             command_filepath = buffer;
      98           0 :             break;
      99             :         }
     100             :     }
     101           0 :     free(custom_scripts_dir_path_pattern);
     102             : 
     103             :         char progname[100];
     104           0 :         int n = readlink("/proc/self/exe", progname, sizeof(progname)-1);
     105           0 :         if (n == -1) {
     106           0 :         strncpy(progname, "unknown", sizeof(progname));
     107           0 :         n = strlen(progname);
     108             :         }
     109           0 :         progname[n] = 0;
     110             : 
     111           0 :         char *p = strrchr(progname, '/');
     112           0 :     if (p != nullptr) {
     113           0 :             *p = 0;
     114             :     } else {
     115           0 :         p = progname;
     116             :     }
     117             : 
     118             :     char output_filepath[80];
     119           0 :     snprintf(output_filepath,
     120             :              ARRAY_SIZE(output_filepath),
     121             :              "%s_%s.%d.out",
     122             :              commandname,
     123             :              p+1,
     124           0 :              (int)getpid());
     125             :     // must fit the command filepath found above, which may now be
     126             :     // an absolute path, plus the output filepath
     127             :     char cmd[PATH_MAX + sizeof(output_filepath) + 32];
     128           0 :         snprintf(cmd,
     129             :              sizeof(cmd),
     130             :              "sh %s %d >%s 2>&1",
     131             :              command_filepath,
     132           0 :              (int)getpid(),
     133             :              output_filepath);
     134           0 :     fprintf(stderr, "Running: %s\n", cmd);
     135             : 
     136           0 :         if (system(cmd)) {
     137           0 :         fprintf(stderr, "Failed\n");
     138           0 :         return;
     139             :     }
     140           0 :     fprintf(stderr, "%s has been run.  Output was:\n", commandname);
     141           0 :     fprintf(stderr, "-------------- begin %s output ----------------\n", commandname);
     142             :     // print the trace on stderr:
     143           0 :     int fd = open(output_filepath, O_RDONLY);
     144           0 :     if (fd == -1) {
     145           0 :         fprintf(stderr, "Failed to open stack dump filepath: %m");
     146           0 :         return;
     147             :     }
     148           0 :     fflush(stderr);  // we are about to write(2) around it
     149             :     char buf[1024]; // let's hope we're not here because we ran out of stack
     150             :     while (true) {
     151           0 :         const ssize_t ret = read(fd, buf, ARRAY_SIZE(buf));
     152           0 :         if (ret == -1) {
     153           0 :             if (errno == EINTR) {
     154             :                 // one of our timers, not a real error
     155           0 :                 continue;
     156             :             }
     157           0 :             fprintf(stderr, "Read error: %m");
     158           0 :             break;
     159             :         }
     160           0 :         if (ret == 0) {
     161           0 :             break;
     162             :         }
     163             :         // write() is allowed to write less than it was asked to - stderr
     164             :         // is a pipe when run from autotest, and a signal can cut a write
     165             :         // short - so keep going until the whole block is out.  Treating a
     166             :         // short write as fatal silently truncated the output, which is
     167             :         // the one thing we came here to collect.
     168           0 :         ssize_t written = 0;
     169           0 :         while (written < ret) {
     170           0 :             const ssize_t wrote = write(2, &buf[written], ret - written);
     171           0 :             if (wrote == -1) {
     172           0 :                 if (errno == EINTR) {
     173           0 :                     continue;
     174             :                 }
     175           0 :                 break;
     176             :             }
     177           0 :             written += wrote;
     178             :         }
     179           0 :         if (written != ret) {
     180           0 :             fprintf(stderr, "Write error after %d of %d bytes: %m\n",
     181             :                     (int)written, (int)ret);
     182           0 :             break;
     183             :         }
     184           0 :     }
     185           0 :     fprintf(stderr, "-------------- end %s output ----------------\n", commandname);
     186           0 :     close(fd);
     187             : }
     188           0 : void dump_stack_trace()
     189             : {
     190           0 :     run_command_on_ownpid("dumpstack.sh");
     191           0 : }
     192           0 : void dump_core_file()
     193             : {
     194           0 :     run_command_on_ownpid("dumpcore.sh");
     195           0 : }
     196             : 
     197  4142240127 : uint32_t micros()
     198             : {
     199  4142240127 :     return micros64() & 0xFFFFFFFF;
     200             : }
     201             : 
     202 13228532818 : uint32_t millis()
     203             : {
     204 13228532818 :     return millis64() & 0xFFFFFFFF;
     205             : }
     206             :     
     207 21998890816 : uint64_t micros64()
     208             : {
     209 21998890816 :     const HALSITL::Scheduler* scheduler = HALSITL::Scheduler::from(hal.scheduler);
     210 21995615970 :     uint64_t stopped_usec = scheduler->stopped_clock_usec();
     211 21993635985 :     if (stopped_usec) {
     212 21993635883 :         return stopped_usec;
     213             :     }
     214             : 
     215             :     struct timespec ts;
     216         102 :     clock_gettime(CLOCK_MONOTONIC, &ts);
     217         102 :     return uint64_div1000(ts_to_nsec(ts) - state.start_time_ns);
     218             : }
     219             : 
     220 13357930611 : uint64_t millis64()
     221             : {
     222 13357930611 :     return uint64_div1000(micros64());
     223             : }
     224             : 
     225             : } // namespace AP_HAL

Generated by: LCOV version 1.14