cmProcess.cxx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmProcess.h"
  4. #include "cmCTest.h"
  5. #include "cmCTestRunTest.h"
  6. #include "cmCTestTestHandler.h"
  7. #include "cmProcessOutput.h"
  8. #include "cmsys/Process.h"
  9. #include <algorithm>
  10. #include <fcntl.h>
  11. #include <iostream>
  12. #include <signal.h>
  13. #include <stdint.h>
  14. #include <string>
  15. #if !defined(_WIN32)
  16. #include <unistd.h>
  17. #endif
  18. #if defined(_WIN32) && !defined(__CYGWIN__)
  19. #include <io.h>
  20. static int cmProcessGetPipes(int* fds)
  21. {
  22. SECURITY_ATTRIBUTES attr;
  23. HANDLE readh, writeh;
  24. attr.nLength = sizeof(attr);
  25. attr.lpSecurityDescriptor = nullptr;
  26. attr.bInheritHandle = FALSE;
  27. if (!CreatePipe(&readh, &writeh, &attr, 0))
  28. return uv_translate_sys_error(GetLastError());
  29. fds[0] = _open_osfhandle((intptr_t)readh, 0);
  30. fds[1] = _open_osfhandle((intptr_t)writeh, 0);
  31. if (fds[0] == -1 || fds[1] == -1) {
  32. CloseHandle(readh);
  33. CloseHandle(writeh);
  34. return uv_translate_sys_error(GetLastError());
  35. }
  36. return 0;
  37. }
  38. #else
  39. #include <errno.h>
  40. static int cmProcessGetPipes(int* fds)
  41. {
  42. if (pipe(fds) == -1) {
  43. return uv_translate_sys_error(errno);
  44. }
  45. if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
  46. fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
  47. close(fds[0]);
  48. close(fds[1]);
  49. return uv_translate_sys_error(errno);
  50. }
  51. return 0;
  52. }
  53. #endif
  54. cmProcess::cmProcess(cmCTestRunTest& runner)
  55. : Runner(runner)
  56. {
  57. this->Timeout = std::chrono::duration<double>::zero();
  58. this->TotalTime = std::chrono::duration<double>::zero();
  59. this->ExitValue = 0;
  60. this->Id = 0;
  61. this->StartTime = std::chrono::steady_clock::time_point();
  62. }
  63. cmProcess::~cmProcess()
  64. {
  65. }
  66. void cmProcess::SetCommand(const char* command)
  67. {
  68. this->Command = command;
  69. }
  70. void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
  71. {
  72. this->Arguments = args;
  73. }
  74. bool cmProcess::StartProcess(uv_loop_t& loop)
  75. {
  76. this->ProcessState = cmProcess::State::Error;
  77. if (this->Command.empty()) {
  78. return false;
  79. }
  80. this->StartTime = std::chrono::steady_clock::now();
  81. this->ProcessArgs.clear();
  82. // put the command as arg0
  83. this->ProcessArgs.push_back(this->Command.c_str());
  84. // now put the command arguments in
  85. for (std::string const& arg : this->Arguments) {
  86. this->ProcessArgs.push_back(arg.c_str());
  87. }
  88. this->ProcessArgs.push_back(nullptr); // null terminate the list
  89. cm::uv_timer_ptr timer;
  90. int status = timer.init(loop, this);
  91. if (status != 0) {
  92. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  93. "Error initializing timer: " << uv_strerror(status)
  94. << std::endl);
  95. return false;
  96. }
  97. cm::uv_pipe_ptr pipe_writer;
  98. cm::uv_pipe_ptr pipe_reader;
  99. pipe_writer.init(loop, 0);
  100. pipe_reader.init(loop, 0, this);
  101. int fds[2] = { -1, -1 };
  102. status = cmProcessGetPipes(fds);
  103. if (status != 0) {
  104. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  105. "Error initializing pipe: " << uv_strerror(status)
  106. << std::endl);
  107. return false;
  108. }
  109. uv_pipe_open(pipe_reader, fds[0]);
  110. uv_pipe_open(pipe_writer, fds[1]);
  111. uv_stdio_container_t stdio[3];
  112. stdio[0].flags = UV_IGNORE;
  113. stdio[1].flags = UV_INHERIT_STREAM;
  114. stdio[1].data.stream = pipe_writer;
  115. stdio[2] = stdio[1];
  116. uv_process_options_t options = uv_process_options_t();
  117. options.file = this->Command.data();
  118. options.args = const_cast<char**>(this->ProcessArgs.data());
  119. options.stdio_count = 3; // in, out and err
  120. options.exit_cb = &cmProcess::OnExitCB;
  121. options.stdio = stdio;
  122. status =
  123. uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB);
  124. if (status != 0) {
  125. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  126. "Error starting read events: " << uv_strerror(status)
  127. << std::endl);
  128. return false;
  129. }
  130. status = this->Process.spawn(loop, options, this);
  131. if (status != 0) {
  132. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, "Process not started\n "
  133. << this->Command << "\n[" << uv_strerror(status) << "]\n");
  134. return false;
  135. }
  136. this->PipeReader = std::move(pipe_reader);
  137. this->Timer = std::move(timer);
  138. this->StartTimer();
  139. this->ProcessState = cmProcess::State::Executing;
  140. return true;
  141. }
  142. void cmProcess::StartTimer()
  143. {
  144. auto properties = this->Runner.GetTestProperties();
  145. auto msec =
  146. std::chrono::duration_cast<std::chrono::milliseconds>(this->Timeout);
  147. if (msec != std::chrono::milliseconds(0) || !properties->ExplicitTimeout) {
  148. this->Timer.start(&cmProcess::OnTimeoutCB,
  149. static_cast<uint64_t>(msec.count()), 0);
  150. }
  151. }
  152. bool cmProcess::Buffer::GetLine(std::string& line)
  153. {
  154. // Scan for the next newline.
  155. for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
  156. if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
  157. // Extract the range first..last as a line.
  158. const char* text = &*this->begin() + this->First;
  159. size_type length = this->Last - this->First;
  160. while (length && text[length - 1] == '\r') {
  161. length--;
  162. }
  163. line.assign(text, length);
  164. // Start a new range for the next line.
  165. ++this->Last;
  166. this->First = Last;
  167. // Return the line extracted.
  168. return true;
  169. }
  170. }
  171. // Available data have been exhausted without a newline.
  172. if (this->First != 0) {
  173. // Move the partial line to the beginning of the buffer.
  174. this->erase(this->begin(), this->begin() + this->First);
  175. this->First = 0;
  176. this->Last = this->size();
  177. }
  178. return false;
  179. }
  180. bool cmProcess::Buffer::GetLast(std::string& line)
  181. {
  182. // Return the partial last line, if any.
  183. if (!this->empty()) {
  184. line.assign(&*this->begin(), this->size());
  185. this->First = this->Last = 0;
  186. this->clear();
  187. return true;
  188. }
  189. return false;
  190. }
  191. void cmProcess::OnReadCB(uv_stream_t* stream, ssize_t nread,
  192. const uv_buf_t* buf)
  193. {
  194. auto self = static_cast<cmProcess*>(stream->data);
  195. self->OnRead(nread, buf);
  196. }
  197. void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
  198. {
  199. std::string line;
  200. if (nread > 0) {
  201. std::string strdata;
  202. cmProcessOutput processOutput(cmProcessOutput::UTF8,
  203. static_cast<unsigned int>(buf->len));
  204. processOutput.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
  205. this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
  206. while (this->Output.GetLine(line)) {
  207. this->Runner.CheckOutput(line);
  208. line.clear();
  209. }
  210. return;
  211. }
  212. // The process will provide no more data.
  213. if (nread != UV_EOF) {
  214. auto error = static_cast<int>(nread);
  215. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  216. "Error reading stream: " << uv_strerror(error) << std::endl);
  217. }
  218. // Look for partial last lines.
  219. if (this->Output.GetLast(line)) {
  220. this->Runner.CheckOutput(line);
  221. }
  222. this->ReadHandleClosed = true;
  223. if (this->ProcessHandleClosed) {
  224. uv_timer_stop(this->Timer);
  225. this->Runner.FinalizeTest();
  226. }
  227. }
  228. void cmProcess::OnAllocateCB(uv_handle_t* handle, size_t suggested_size,
  229. uv_buf_t* buf)
  230. {
  231. auto self = static_cast<cmProcess*>(handle->data);
  232. self->OnAllocate(suggested_size, buf);
  233. }
  234. void cmProcess::OnAllocate(size_t suggested_size, uv_buf_t* buf)
  235. {
  236. if (this->Buf.size() < suggested_size) {
  237. this->Buf.resize(suggested_size);
  238. }
  239. *buf =
  240. uv_buf_init(this->Buf.data(), static_cast<unsigned int>(this->Buf.size()));
  241. }
  242. void cmProcess::OnTimeoutCB(uv_timer_t* timer)
  243. {
  244. auto self = static_cast<cmProcess*>(timer->data);
  245. self->OnTimeout();
  246. }
  247. void cmProcess::OnTimeout()
  248. {
  249. if (this->ProcessState != cmProcess::State::Executing) {
  250. return;
  251. }
  252. this->ProcessState = cmProcess::State::Expired;
  253. bool const was_still_reading = !this->ReadHandleClosed;
  254. if (!this->ReadHandleClosed) {
  255. this->ReadHandleClosed = true;
  256. this->PipeReader.reset();
  257. }
  258. if (!this->ProcessHandleClosed) {
  259. // Kill the child and let our on-exit handler finish the test.
  260. cmsysProcess_KillPID(static_cast<unsigned long>(this->Process->pid));
  261. } else if (was_still_reading) {
  262. // Our on-exit handler already ran but did not finish the test
  263. // because we were still reading output. We've just dropped
  264. // our read handler, so we need to finish the test now.
  265. this->Runner.FinalizeTest();
  266. }
  267. }
  268. void cmProcess::OnExitCB(uv_process_t* process, int64_t exit_status,
  269. int term_signal)
  270. {
  271. auto self = static_cast<cmProcess*>(process->data);
  272. self->OnExit(exit_status, term_signal);
  273. }
  274. void cmProcess::OnExit(int64_t exit_status, int term_signal)
  275. {
  276. if (this->ProcessState != cmProcess::State::Expired) {
  277. if (
  278. #if defined(_WIN32)
  279. ((DWORD)exit_status & 0xF0000000) == 0xC0000000
  280. #else
  281. term_signal != 0
  282. #endif
  283. ) {
  284. this->ProcessState = cmProcess::State::Exception;
  285. } else {
  286. this->ProcessState = cmProcess::State::Exited;
  287. }
  288. }
  289. // Record exit information.
  290. this->ExitValue = static_cast<int>(exit_status);
  291. this->Signal = term_signal;
  292. this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
  293. // Because of a processor clock scew the runtime may become slightly
  294. // negative. If someone changed the system clock while the process was
  295. // running this may be even more. Make sure not to report a negative
  296. // duration here.
  297. if (this->TotalTime <= std::chrono::duration<double>::zero()) {
  298. this->TotalTime = std::chrono::duration<double>::zero();
  299. }
  300. this->ProcessHandleClosed = true;
  301. if (this->ReadHandleClosed) {
  302. uv_timer_stop(this->Timer);
  303. this->Runner.FinalizeTest();
  304. }
  305. }
  306. cmProcess::State cmProcess::GetProcessStatus()
  307. {
  308. return this->ProcessState;
  309. }
  310. void cmProcess::ChangeTimeout(std::chrono::duration<double> t)
  311. {
  312. this->Timeout = t;
  313. this->StartTimer();
  314. }
  315. void cmProcess::ResetStartTime()
  316. {
  317. this->StartTime = std::chrono::steady_clock::now();
  318. }
  319. cmProcess::Exception cmProcess::GetExitException()
  320. {
  321. auto exception = Exception::None;
  322. #if defined(_WIN32) && !defined(__CYGWIN__)
  323. auto exit_code = (DWORD) this->ExitValue;
  324. if ((exit_code & 0xF0000000) != 0xC0000000) {
  325. return exception;
  326. }
  327. if (exit_code) {
  328. switch (exit_code) {
  329. case STATUS_DATATYPE_MISALIGNMENT:
  330. case STATUS_ACCESS_VIOLATION:
  331. case STATUS_IN_PAGE_ERROR:
  332. case STATUS_INVALID_HANDLE:
  333. case STATUS_NONCONTINUABLE_EXCEPTION:
  334. case STATUS_INVALID_DISPOSITION:
  335. case STATUS_ARRAY_BOUNDS_EXCEEDED:
  336. case STATUS_STACK_OVERFLOW:
  337. exception = Exception::Fault;
  338. break;
  339. case STATUS_FLOAT_DENORMAL_OPERAND:
  340. case STATUS_FLOAT_DIVIDE_BY_ZERO:
  341. case STATUS_FLOAT_INEXACT_RESULT:
  342. case STATUS_FLOAT_INVALID_OPERATION:
  343. case STATUS_FLOAT_OVERFLOW:
  344. case STATUS_FLOAT_STACK_CHECK:
  345. case STATUS_FLOAT_UNDERFLOW:
  346. #ifdef STATUS_FLOAT_MULTIPLE_FAULTS
  347. case STATUS_FLOAT_MULTIPLE_FAULTS:
  348. #endif
  349. #ifdef STATUS_FLOAT_MULTIPLE_TRAPS
  350. case STATUS_FLOAT_MULTIPLE_TRAPS:
  351. #endif
  352. case STATUS_INTEGER_DIVIDE_BY_ZERO:
  353. case STATUS_INTEGER_OVERFLOW:
  354. exception = Exception::Numerical;
  355. break;
  356. case STATUS_CONTROL_C_EXIT:
  357. exception = Exception::Interrupt;
  358. break;
  359. case STATUS_ILLEGAL_INSTRUCTION:
  360. case STATUS_PRIVILEGED_INSTRUCTION:
  361. exception = Exception::Illegal;
  362. break;
  363. default:
  364. exception = Exception::Other;
  365. }
  366. }
  367. #else
  368. if (this->Signal) {
  369. switch (this->Signal) {
  370. case SIGSEGV:
  371. exception = Exception::Fault;
  372. break;
  373. case SIGFPE:
  374. exception = Exception::Numerical;
  375. break;
  376. case SIGINT:
  377. exception = Exception::Interrupt;
  378. break;
  379. case SIGILL:
  380. exception = Exception::Illegal;
  381. break;
  382. default:
  383. exception = Exception::Other;
  384. }
  385. }
  386. #endif
  387. return exception;
  388. }
  389. std::string cmProcess::GetExitExceptionString()
  390. {
  391. std::string exception_str;
  392. #if defined(_WIN32)
  393. switch (this->ExitValue) {
  394. case STATUS_CONTROL_C_EXIT:
  395. exception_str = "User interrupt";
  396. break;
  397. case STATUS_FLOAT_DENORMAL_OPERAND:
  398. exception_str = "Floating-point exception (denormal operand)";
  399. break;
  400. case STATUS_FLOAT_DIVIDE_BY_ZERO:
  401. exception_str = "Divide-by-zero";
  402. break;
  403. case STATUS_FLOAT_INEXACT_RESULT:
  404. exception_str = "Floating-point exception (inexact result)";
  405. break;
  406. case STATUS_FLOAT_INVALID_OPERATION:
  407. exception_str = "Invalid floating-point operation";
  408. break;
  409. case STATUS_FLOAT_OVERFLOW:
  410. exception_str = "Floating-point overflow";
  411. break;
  412. case STATUS_FLOAT_STACK_CHECK:
  413. exception_str = "Floating-point stack check failed";
  414. break;
  415. case STATUS_FLOAT_UNDERFLOW:
  416. exception_str = "Floating-point underflow";
  417. break;
  418. #ifdef STATUS_FLOAT_MULTIPLE_FAULTS
  419. case STATUS_FLOAT_MULTIPLE_FAULTS:
  420. exception_str = "Floating-point exception (multiple faults)";
  421. break;
  422. #endif
  423. #ifdef STATUS_FLOAT_MULTIPLE_TRAPS
  424. case STATUS_FLOAT_MULTIPLE_TRAPS:
  425. exception_str = "Floating-point exception (multiple traps)";
  426. break;
  427. #endif
  428. case STATUS_INTEGER_DIVIDE_BY_ZERO:
  429. exception_str = "Integer divide-by-zero";
  430. break;
  431. case STATUS_INTEGER_OVERFLOW:
  432. exception_str = "Integer overflow";
  433. break;
  434. case STATUS_DATATYPE_MISALIGNMENT:
  435. exception_str = "Datatype misalignment";
  436. break;
  437. case STATUS_ACCESS_VIOLATION:
  438. exception_str = "Access violation";
  439. break;
  440. case STATUS_IN_PAGE_ERROR:
  441. exception_str = "In-page error";
  442. break;
  443. case STATUS_INVALID_HANDLE:
  444. exception_str = "Invalid handle";
  445. break;
  446. case STATUS_NONCONTINUABLE_EXCEPTION:
  447. exception_str = "Noncontinuable exception";
  448. break;
  449. case STATUS_INVALID_DISPOSITION:
  450. exception_str = "Invalid disposition";
  451. break;
  452. case STATUS_ARRAY_BOUNDS_EXCEEDED:
  453. exception_str = "Array bounds exceeded";
  454. break;
  455. case STATUS_STACK_OVERFLOW:
  456. exception_str = "Stack overflow";
  457. break;
  458. case STATUS_ILLEGAL_INSTRUCTION:
  459. exception_str = "Illegal instruction";
  460. break;
  461. case STATUS_PRIVILEGED_INSTRUCTION:
  462. exception_str = "Privileged instruction";
  463. break;
  464. case STATUS_NO_MEMORY:
  465. default:
  466. char buf[1024];
  467. _snprintf(buf, 1024, "Exit code 0x%x\n", this->ExitValue);
  468. exception_str.assign(buf);
  469. }
  470. #else
  471. switch (this->Signal) {
  472. #ifdef SIGSEGV
  473. case SIGSEGV:
  474. exception_str = "Segmentation fault";
  475. break;
  476. #endif
  477. #ifdef SIGBUS
  478. #if !defined(SIGSEGV) || SIGBUS != SIGSEGV
  479. case SIGBUS:
  480. exception_str = "Bus error";
  481. break;
  482. #endif
  483. #endif
  484. #ifdef SIGFPE
  485. case SIGFPE:
  486. exception_str = "Floating-point exception";
  487. break;
  488. #endif
  489. #ifdef SIGILL
  490. case SIGILL:
  491. exception_str = "Illegal instruction";
  492. break;
  493. #endif
  494. #ifdef SIGINT
  495. case SIGINT:
  496. exception_str = "User interrupt";
  497. break;
  498. #endif
  499. #ifdef SIGABRT
  500. case SIGABRT:
  501. exception_str = "Child aborted";
  502. break;
  503. #endif
  504. #ifdef SIGKILL
  505. case SIGKILL:
  506. exception_str = "Child killed";
  507. break;
  508. #endif
  509. #ifdef SIGTERM
  510. case SIGTERM:
  511. exception_str = "Child terminated";
  512. break;
  513. #endif
  514. #ifdef SIGHUP
  515. case SIGHUP:
  516. exception_str = "SIGHUP";
  517. break;
  518. #endif
  519. #ifdef SIGQUIT
  520. case SIGQUIT:
  521. exception_str = "SIGQUIT";
  522. break;
  523. #endif
  524. #ifdef SIGTRAP
  525. case SIGTRAP:
  526. exception_str = "SIGTRAP";
  527. break;
  528. #endif
  529. #ifdef SIGIOT
  530. #if !defined(SIGABRT) || SIGIOT != SIGABRT
  531. case SIGIOT:
  532. exception_str = "SIGIOT";
  533. break;
  534. #endif
  535. #endif
  536. #ifdef SIGUSR1
  537. case SIGUSR1:
  538. exception_str = "SIGUSR1";
  539. break;
  540. #endif
  541. #ifdef SIGUSR2
  542. case SIGUSR2:
  543. exception_str = "SIGUSR2";
  544. break;
  545. #endif
  546. #ifdef SIGPIPE
  547. case SIGPIPE:
  548. exception_str = "SIGPIPE";
  549. break;
  550. #endif
  551. #ifdef SIGALRM
  552. case SIGALRM:
  553. exception_str = "SIGALRM";
  554. break;
  555. #endif
  556. #ifdef SIGSTKFLT
  557. case SIGSTKFLT:
  558. exception_str = "SIGSTKFLT";
  559. break;
  560. #endif
  561. #ifdef SIGCHLD
  562. case SIGCHLD:
  563. exception_str = "SIGCHLD";
  564. break;
  565. #elif defined(SIGCLD)
  566. case SIGCLD:
  567. exception_str = "SIGCLD";
  568. break;
  569. #endif
  570. #ifdef SIGCONT
  571. case SIGCONT:
  572. exception_str = "SIGCONT";
  573. break;
  574. #endif
  575. #ifdef SIGSTOP
  576. case SIGSTOP:
  577. exception_str = "SIGSTOP";
  578. break;
  579. #endif
  580. #ifdef SIGTSTP
  581. case SIGTSTP:
  582. exception_str = "SIGTSTP";
  583. break;
  584. #endif
  585. #ifdef SIGTTIN
  586. case SIGTTIN:
  587. exception_str = "SIGTTIN";
  588. break;
  589. #endif
  590. #ifdef SIGTTOU
  591. case SIGTTOU:
  592. exception_str = "SIGTTOU";
  593. break;
  594. #endif
  595. #ifdef SIGURG
  596. case SIGURG:
  597. exception_str = "SIGURG";
  598. break;
  599. #endif
  600. #ifdef SIGXCPU
  601. case SIGXCPU:
  602. exception_str = "SIGXCPU";
  603. break;
  604. #endif
  605. #ifdef SIGXFSZ
  606. case SIGXFSZ:
  607. exception_str = "SIGXFSZ";
  608. break;
  609. #endif
  610. #ifdef SIGVTALRM
  611. case SIGVTALRM:
  612. exception_str = "SIGVTALRM";
  613. break;
  614. #endif
  615. #ifdef SIGPROF
  616. case SIGPROF:
  617. exception_str = "SIGPROF";
  618. break;
  619. #endif
  620. #ifdef SIGWINCH
  621. case SIGWINCH:
  622. exception_str = "SIGWINCH";
  623. break;
  624. #endif
  625. #ifdef SIGPOLL
  626. case SIGPOLL:
  627. exception_str = "SIGPOLL";
  628. break;
  629. #endif
  630. #ifdef SIGIO
  631. #if !defined(SIGPOLL) || SIGIO != SIGPOLL
  632. case SIGIO:
  633. exception_str = "SIGIO";
  634. break;
  635. #endif
  636. #endif
  637. #ifdef SIGPWR
  638. case SIGPWR:
  639. exception_str = "SIGPWR";
  640. break;
  641. #endif
  642. #ifdef SIGSYS
  643. case SIGSYS:
  644. exception_str = "SIGSYS";
  645. break;
  646. #endif
  647. #ifdef SIGUNUSED
  648. #if !defined(SIGSYS) || SIGUNUSED != SIGSYS
  649. case SIGUNUSED:
  650. exception_str = "SIGUNUSED";
  651. break;
  652. #endif
  653. #endif
  654. default:
  655. exception_str = "Signal ";
  656. exception_str += std::to_string(this->Signal);
  657. }
  658. #endif
  659. return exception_str;
  660. }