blob: 4b49725dd46baaec593c3231a89f7d7f8943f4e7 [file] [log] [blame]
Brian Silverman1a675112016-02-20 20:42:49 -05001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2016. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
Brian Silverman26e4e522015-12-17 01:56:40 -05007
8/* Copyright (c) FIRST 2008. All Rights Reserved. */
9/* Open Source Software - may be modified and shared by FRC teams. The code */
10/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
11/*----------------------------------------------------------------------------*/
12
13#include "Utility.h"
14
15#include "Timer.h"
16#include "simulation/simTime.h"
17#include <stdio.h>
18#include <string.h>
19
20#include <iostream>
21#include <sstream>
22#include <cstdio>
23#include <cstdlib>
24#include <cstring>
Brian Silverman1a675112016-02-20 20:42:49 -050025#if not defined(_WIN32)
Brian Silverman26e4e522015-12-17 01:56:40 -050026 #include <execinfo.h>
27 #include <cxxabi.h>
28#endif
29
30static bool stackTraceEnabled = false;
31static bool suspendOnAssertEnabled = false;
32
33/**
34 * Enable Stack trace after asserts.
35 */
36void wpi_stackTraceOnAssertEnable(bool enabled)
37{
38 stackTraceEnabled = enabled;
39}
40
41/**
42 * Enable suspend on asssert.
43 * If enabled, the user task will be suspended whenever an assert fails. This
44 * will allow the user to attach to the task with the debugger and examine variables
45 * around the failure.
46 */
47void wpi_suspendOnAssertEnabled(bool enabled)
48{
49 suspendOnAssertEnabled = enabled;
50}
51
52static void wpi_handleTracing()
53{
54 // if (stackTraceEnabled)
55 // {
56 // printf("\n-----------<Stack Trace>----------------\n");
57 // printCurrentStackTrace();
58 // }
59 printf("\n");
60}
61
62/**
63 * Assert implementation.
64 * This allows breakpoints to be set on an assert.
65 * The users don't call this, but instead use the wpi_assert macros in Utility.h.
66 */
Brian Silverman1a675112016-02-20 20:42:49 -050067bool wpi_assert_impl(bool conditionValue, const char *conditionText,
68 const char *message, const char *fileName,
69 uint32_t lineNumber, const char *funcName) {
Brian Silverman26e4e522015-12-17 01:56:40 -050070 if (!conditionValue) {
Brian Silverman1a675112016-02-20 20:42:49 -050071 std::stringstream errorStream;
Brian Silverman26e4e522015-12-17 01:56:40 -050072
Brian Silverman1a675112016-02-20 20:42:49 -050073 errorStream << "Assertion \"" << conditionText << "\" ";
74 errorStream << "on line " << lineNumber << " ";
75 errorStream << "of " << basename(fileName) << " ";
76
77 if (message[0] != '\0') {
78 errorStream << "failed: " << message << std::endl;
Brian Silverman26e4e522015-12-17 01:56:40 -050079 } else {
Brian Silverman1a675112016-02-20 20:42:49 -050080 errorStream << "failed." << std::endl;
Brian Silverman26e4e522015-12-17 01:56:40 -050081 }
82
83 // Print to console and send to remote dashboard
Brian Silverman1a675112016-02-20 20:42:49 -050084 std::cout << "\n\n>>>>" << errorStream.str();
Brian Silverman26e4e522015-12-17 01:56:40 -050085 wpi_handleTracing();
86 }
Brian Silverman1a675112016-02-20 20:42:49 -050087
Brian Silverman26e4e522015-12-17 01:56:40 -050088 return conditionValue;
89}
90
91/**
92 * Common error routines for wpi_assertEqual_impl and wpi_assertNotEqual_impl
93 * This should not be called directly; it should only be used by wpi_assertEqual_impl
94 * and wpi_assertNotEqual_impl.
95 */
96void wpi_assertEqual_common_impl(int valueA, int valueB,
97 const std::string &equalityType,
98 const std::string &message,
99 const std::string &fileName,
100 uint32_t lineNumber,
101 const std::string &funcName) {
102 // Error string buffer
103 std::stringstream error;
104
105 // If an error message was specified, include it
106 // Build error string
107 if (message.size() > 0) {
108 error << "Assertion failed: \"" << message << "\", \"" << valueA << "\" "
109 << equalityType << " \"" << valueB << "\" in " << funcName << "() in "
110 << fileName << " at line " << lineNumber << "\n";
111 } else {
112 error << "Assertion failed: \"" << valueA << "\" " << equalityType << " \""
113 << valueB << "\" in " << funcName << "() in " << fileName
114 << " at line " << lineNumber << "\n";
115 }
116
117 // Print to console and send to remote dashboard
118 std::cout << "\n\n>>>>" << error.str();
119
120 wpi_handleTracing();
121}
122
123/**
124 * Assert equal implementation.
125 * This determines whether the two given integers are equal. If not,
126 * the value of each is printed along with an optional message string.
127 * The users don't call this, but instead use the wpi_assertEqual macros in Utility.h.
128 */
129bool wpi_assertEqual_impl(int valueA,
130 int valueB,
131 const std::string &message,
132 const std::string &fileName,
133 uint32_t lineNumber,
134 const std::string &funcName)
135{
136 if(!(valueA == valueB))
137 {
138 wpi_assertEqual_common_impl(valueA, valueB, "!=", message, fileName, lineNumber, funcName);
139 }
140 return valueA == valueB;
141}
142
143/**
144 * Assert not equal implementation.
145 * This determines whether the two given integers are equal. If so,
146 * the value of each is printed along with an optional message string.
147 * The users don't call this, but instead use the wpi_assertNotEqual macros in Utility.h.
148 */
149bool wpi_assertNotEqual_impl(int valueA,
150 int valueB,
151 const std::string &message,
152 const std::string &fileName,
153 uint32_t lineNumber,
154 const std::string &funcName)
155{
156 if(!(valueA != valueB))
157 {
158 wpi_assertEqual_common_impl(valueA, valueB, "==", message, fileName, lineNumber, funcName);
159 }
160 return valueA != valueB;
161}
162
163/**
164 * Read the microsecond-resolution timer on the FPGA.
165 *
166 * @return The current time in microseconds according to the FPGA (since FPGA reset).
167 */
Brian Silverman1a675112016-02-20 20:42:49 -0500168uint64_t GetFPGATime()
Brian Silverman26e4e522015-12-17 01:56:40 -0500169{
170 return wpilib::internal::simTime * 1e6;
171}
172
173//TODO: implement symbol demangling and backtrace on windows
Brian Silverman1a675112016-02-20 20:42:49 -0500174#if not defined(_WIN32)
Brian Silverman26e4e522015-12-17 01:56:40 -0500175
176/**
177 * Demangle a C++ symbol, used for printing stack traces.
178 */
179static std::string demangle(char const *mangledSymbol)
180{
181 char buffer[256];
182 size_t length;
183 int status;
184
185 if(sscanf(mangledSymbol, "%*[^(]%*[^_]%255[^)+]", buffer))
186 {
187 char *symbol = abi::__cxa_demangle(buffer, nullptr, &length, &status);
188
189 if(status == 0)
190 {
191 return symbol;
192 }
193 else
194 {
195 // If the symbol couldn't be demangled, it's probably a C function,
196 // so just return it as-is.
197 return buffer;
198 }
199 }
200
201
202 // If everything else failed, just return the mangled symbol
203 return mangledSymbol;
204}
205
206/**
207 * Get a stack trace, ignoring the first "offset" symbols.
208 */
209std::string GetStackTrace(uint32_t offset)
210{
211 void *stackTrace[128];
212 int stackSize = backtrace(stackTrace, 128);
213 char **mangledSymbols = backtrace_symbols(stackTrace, stackSize);
214 std::stringstream trace;
215
216 for(int i = offset; i < stackSize; i++)
217 {
218 // Only print recursive functions once in a row.
219 if(i == 0 ||stackTrace[i] != stackTrace[i - 1])
220 {
221 trace << "\tat " << demangle(mangledSymbols[i]) << std::endl;
222 }
223 }
224
225 free(mangledSymbols);
226
227 return trace.str();
228}
229
230#else
231static std::string demangle(char const *mangledSymbol)
232{
233 return "no demangling on windows";
234}
235std::string GetStackTrace(uint32_t offset)
236{
237 return "no stack trace on windows";
238}
239#endif