1 /* Copyright (c) 2010-2016. The SimGrid Team.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
9 * This file contains functions that aid users to debug their lua scripts; for instance,
10 * tables can be easily output and values are represented in a human-readable way. (For instance,
11 * a NULL value becomes the string "nil").
14 /* SimGrid Lua debug functions */
18 #include "lua_utils.h"
21 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua_debug, bindings, "Lua helper functions");
24 * @brief Returns a string representation of a value in the Lua stack.
26 * This function is for debugging purposes.
27 * It always returns the same pointer.
29 * @param L the Lua state
30 * @param index index in the stack
31 * @return a string representation of the value at this index
33 const char* sglua_tostring(lua_State* L, int index) {
37 switch (lua_type(L, index)) {
44 sprintf(buff, "%.3f", lua_tonumber(L, index));
48 sprintf(buff, "%s", lua_toboolean(L, index) ? "true" : "false");
52 snprintf(buff, 63, "'%s'", lua_tostring(L, index));
56 if (lua_iscfunction(L, index)) {
57 sprintf(buff, "C-function");
60 sprintf(buff, "function");
65 sprintf(buff, "table(%p)", lua_topointer(L, index));
68 case LUA_TLIGHTUSERDATA:
70 sprintf(buff, "userdata(%p)", lua_touserdata(L, index));
74 sprintf(buff, "thread");
80 static int sglua_dump_table(lua_State* L) {
81 int argc = lua_gettop(L);
83 for (int i = 1; i < argc; i++) {
84 if (lua_istable(L, i)) {
85 lua_pushnil(L); /* table nil */
87 //lua_next pops the topmost element from the stack and
88 //gets the next pair from the table
89 while (lua_next(L, -1)) { /* table key val */
90 // we need to copy here, as a cast from "Number" to "String"
91 // could happen in Lua.
92 // see remark in the lua manual, function "lua_tolstring"
93 // http://www.lua.org/manual/5.3/manual.html#lua_tolstring
95 lua_pushvalue(L, -2); /* table key val key */
97 const char *key = lua_tostring(L, -1); /* table key val */
98 const char *val = lua_tostring(L, -1); /* table key */
100 XBT_DEBUG("%s => %s", key, val);
103 lua_settop(L, argc); // Remove everything except the initial arguments
111 * @brief Returns a string composed of the specified number of spaces.
113 * This function can be used to indent strings for debugging purposes.
114 * It always returns the same pointer.
116 * @param length length of the string
117 * @return a string of this length with only spaces
119 const char* sglua_get_spaces(int length) {
121 static char spaces[128];
123 xbt_assert(length >= 0 && length < 128,
124 "Invalid indentation length: %d", length);
126 memset(spaces, ' ', length);
128 spaces[length] = '\0';
133 * @brief Returns a string representation of a key-value pair.
135 * It always returns the same pointer.
137 * @param L the Lua state
138 * @param key_index index of the key (in the lua stack)
139 * @param value_index index of the value (in the lua stack)
140 * @return a string representation of the key-value pair
142 const char* sglua_keyvalue_tostring(lua_State* L, int key_index, int value_index) {
144 static char buff[64];
145 /* value_tostring also always returns the same pointer */
146 int len = snprintf(buff, 63, "[%s] -> ", sglua_tostring(L, key_index));
147 snprintf(buff + len, 63 - len, "%s", sglua_tostring(L, value_index));
152 * @brief Dumps the Lua stack if debug logs are enabled.
153 * @param msg a message to print
154 * @param L a Lua state
156 void sglua_stack_dump(lua_State* L, const char* msg)
158 if (XBT_LOG_ISENABLED(lua_debug, xbt_log_priority_debug)) {
161 int top = lua_gettop(L);
166 for (int i = 1; i <= top; i++) { /* repeat for each level */
167 p += sprintf(p, "%s ", sglua_tostring(L, i));
170 XBT_DEBUG("%s%s", msg, buff);
175 * \brief Like luaL_checkudata, with additional debug logs.
177 * This function is for debugging purposes only.
179 * \param L a lua state
180 * \param ud index of the userdata to check in the stack
181 * \param tname key of the metatable of this userdata in the registry
183 void* sglua_checkudata_debug(lua_State* L, int ud, const char* tname)
185 XBT_DEBUG("Checking the userdata: ud = %d", ud);
186 sglua_stack_dump(L, "my_checkudata: ");
187 void* p = lua_touserdata(L, ud);
188 lua_getfield(L, LUA_REGISTRYINDEX, tname);
189 const void* correct_mt = lua_topointer(L, -1);
191 int has_mt = lua_getmetatable(L, ud);
192 XBT_DEBUG("Checking the userdata: has metatable ? %d", has_mt);
193 const void* actual_mt = NULL;
195 actual_mt = lua_topointer(L, -1);
198 XBT_DEBUG("Checking the task's metatable: expected %p, found %p", correct_mt, actual_mt);
199 sglua_stack_dump(L, "my_checkudata: ");
201 if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2))
202 XBT_ERROR("Error: Userdata is NULL, couldn't find metatable or top of stack does not equal element below it.");
208 * @brief Writes the specified data into a memory buffer.
210 * This function is a valid lua_Writer that writes into a memory buffer passed
213 * @param L a lua state
214 * @param source some data
215 * @param sz number of bytes of data
216 * @param user_data the memory buffer to write
218 int sglua_memory_writer(lua_State* L, const void* source, size_t size,
221 sglua_buffer_t buffer = (sglua_buffer_t) userdata;
222 while (buffer->capacity < buffer->size + size) {
223 buffer->capacity *= 2;
224 buffer->data = (char*)xbt_realloc(buffer->data, buffer->capacity);
226 memcpy(buffer->data + buffer->size, source, size);
227 buffer->size += size;