[tarantool-patches] [PATCH 3/3] Show names of Lua functions in backtraces

  • From: Georgy Kirichenko <georgy@xxxxxxxxxxxxx>
  • To: tarantool-patches@xxxxxxxxxxxxx
  • Date: Wed, 10 Oct 2018 19:39:26 +0300

Trace corresponding Lua state as well as normal C stack frames while
fiber backtracing. This might be useful for debugging purposes.

Fixes: #3538
---
 src/lua/fiber.c         | 86 +++++++++++++++++++++++++++++++++++------
 test/app/fiber.result   | 33 ++++++++++++++++
 test/app/fiber.test.lua | 12 ++++++
 3 files changed, 120 insertions(+), 11 deletions(-)

diff --git a/src/lua/fiber.c b/src/lua/fiber.c
index 147add89b..428c2f938 100644
--- a/src/lua/fiber.c
+++ b/src/lua/fiber.c
@@ -178,20 +178,79 @@ lbox_fiber_id(struct lua_State *L)
        return 1;
 }
 
+/**
+ * Lua fiber traceback context.
+ */
+struct lua_fiber_tb_ctx {
+       /* Lua stack to push values. */
+       struct lua_State *L;
+       /* Lua stack to trace. */
+       struct lua_State *R;
+       /* Current Lua frame. */
+       int lua_frame;
+       /* Count of traced frames (both C and Lua). */
+       int tb_frame;
+};
+
 #ifdef ENABLE_BACKTRACE
-static int
-fiber_backtrace_cb(int frameno, void *frameret, const char *func, size_t 
offset, void *cb_ctx)
+static void
+dump_lua_frame(struct lua_State *L, lua_Debug *ar, int tb_frame, int lua_frame)
 {
        char buf[512];
-       int l = snprintf(buf, sizeof(buf), "#%-2d %p in ", frameno, frameret);
-       if (func)
-               snprintf(buf + l, sizeof(buf) - l, "%s+%zu", func, offset);
-       else
-               snprintf(buf + l, sizeof(buf) - l, "?");
-       struct lua_State *L = (struct lua_State*)cb_ctx;
-       lua_pushnumber(L, frameno + 1);
+       snprintf(buf, sizeof(buf), "LUA#%-2d %s in %s at line %i",
+                lua_frame + 1,
+                ar->name != NULL ? ar->name : "(unnamed)",
+                ar->source, ar->currentline);
+       lua_pushnumber(L, tb_frame);
        lua_pushstring(L, buf);
        lua_settable(L, -3);
+}
+
+static int
+fiber_backtrace_cb(int frameno, void *frameret, const char *func, size_t 
offset, void *cb_ctx)
+{
+       struct lua_fiber_tb_ctx *tb_ctx = (struct lua_fiber_tb_ctx *)cb_ctx;
+       struct lua_State *L = tb_ctx->L;
+       if (strstr(func, "lj_BC_FUNCC") == func) {
+               /* We are in the LUA vm. */
+               lua_Debug ar;
+               while (tb_ctx->R && lua_getstack(tb_ctx->R, tb_ctx->lua_frame, 
&ar) > 0) {
+                       /* Skip all following C-frames. */
+                       lua_getinfo(tb_ctx->R, "Sln", &ar);
+                       if (*ar.what != 'C')
+                               break;
+                       if (ar.name != NULL) {
+                               /* Dump frame if it is a C built-in call. */
+                               tb_ctx->tb_frame++;
+                               dump_lua_frame(L, &ar, tb_ctx->tb_frame,
+                                              tb_ctx->lua_frame);
+                       }
+                       tb_ctx->lua_frame++;
+               }
+               while (tb_ctx->R && lua_getstack(tb_ctx->R, tb_ctx->lua_frame, 
&ar) > 0) {
+                       /* Trace Lua frame. */
+                       lua_getinfo(tb_ctx->R, "Sln", &ar);
+                       if (*ar.what == 'C') {
+                               break;
+                       }
+                       tb_ctx->tb_frame++;
+                       dump_lua_frame(L, &ar, tb_ctx->tb_frame,
+                                      tb_ctx->lua_frame);
+                       tb_ctx->lua_frame++;
+               }
+       } else {
+               char buf[512];
+               int l = snprintf(buf, sizeof(buf), "#%-2d %p in ",
+                                frameno + 1, frameret);
+               if (func)
+                       snprintf(buf + l, sizeof(buf) - l, "%s+%zu", func, 
offset);
+               else
+                       snprintf(buf + l, sizeof(buf) - l, "?");
+               tb_ctx->tb_frame++;
+               lua_pushnumber(L, tb_ctx->tb_frame);
+               lua_pushstring(L, buf);
+               lua_settable(L, -3);
+       }
        return 0;
 }
 #endif
@@ -229,10 +288,15 @@ lbox_fiber_statof(struct fiber *f, void *cb_ctx, bool 
backtrace)
 
        if (backtrace) {
 #ifdef ENABLE_BACKTRACE
+               struct lua_fiber_tb_ctx tb_ctx;
+               tb_ctx.L = L;
+               tb_ctx.R = f->storage.lua.stack;
+               tb_ctx.lua_frame = 0;
+               tb_ctx.tb_frame = 0;
                lua_pushstring(L, "backtrace");
                lua_newtable(L);
-               if (f != fiber())
-                       backtrace_foreach(fiber_backtrace_cb, &f->ctx, L);
+               backtrace_foreach(fiber_backtrace_cb,
+                                 f != fiber() ? &f->ctx : NULL, &tb_ctx);
                lua_settable(L, -3);
 #endif /* ENABLE_BACKTRACE */
        }
diff --git a/test/app/fiber.result b/test/app/fiber.result
index 77144e661..1a7827fa1 100644
--- a/test/app/fiber.result
+++ b/test/app/fiber.result
@@ -849,6 +849,39 @@ f2:cancel()
 f3:cancel()
 ---
 ...
+function sf1() loop() end
+---
+...
+function sf2() sf1() end
+---
+...
+function sf3() sf2() end
+---
+...
+f1 = fiber.create(sf3)
+---
+...
+info = fiber.info()
+---
+...
+backtrace = info[f1:id()].backtrace
+---
+...
+bt_str = table.concat(backtrace, '\n')
+---
+...
+bt_str:find('sf1') ~= nil
+---
+- true
+...
+bt_str:find('loop') ~= nil
+---
+- true
+...
+bt_str:find('sf3') ~= nil
+---
+- true
+...
 -- # gh-666: nulls in output
 --
 getmetatable(fiber.info())
diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua
index 98a136090..9df751cc8 100644
--- a/test/app/fiber.test.lua
+++ b/test/app/fiber.test.lua
@@ -334,6 +334,18 @@ f1:cancel()
 f2:cancel()
 f3:cancel()
 
+function sf1() loop() end
+function sf2() sf1() end
+function sf3() sf2() end
+f1 = fiber.create(sf3)
+
+info = fiber.info()
+backtrace = info[f1:id()].backtrace
+bt_str = table.concat(backtrace, '\n')
+bt_str:find('sf1') ~= nil
+bt_str:find('loop') ~= nil
+bt_str:find('sf3') ~= nil
+
 -- # gh-666: nulls in output
 --
 getmetatable(fiber.info())
-- 
2.19.1


Other related posts: