{"id":329306,"date":"2023-06-19T07:00:00","date_gmt":"2023-06-19T07:00:00","guid":{"rendered":"http:\/\/itteacheritfreelance.hk\/wordpress\/?guid=ccb2aaa86ba6ab3269f9f327554f67a2"},"modified":"2023-06-19T07:00:00","modified_gmt":"2023-06-19T07:00:00","slug":"debugging-in-gdb-create-custom-stack-winders","status":"publish","type":"post","link":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/2023\/06\/19\/debugging-in-gdb-create-custom-stack-winders\/","title":{"rendered":"Debugging in GDB: Create custom stack winders"},"content":{"rendered":"<p class=\"syndicated-attribution\"><meta name= \\\"keywords \\\" content= \\\"\u96fb\u5b50\u8a08\u7b97\u6a5f, \u6559\u80b2, IT \u96fb\u8166\u73ed,\u96fb\u8166\u88dc\u7fd2\uff0c \u96fb\u8166\u73ed\uff0c \u5bb6\u6559\uff0c \u79c1\u4eba\u8001\u5e2b\uff0c \u8cc7\u8a0a\u6280\u8853\uff0c \u7a0b\u5e8f\u8a2d\u8a08\uff0c \u96fb\u5b50\u8a08\u7b97\u6a5f\uff0c \u904a\u6232\uff0c \u860b\u679c\uff0c \u96fb\u5f71\uff0c \u8a08\u7b97\u6a5f\uff0c\u7de8\u78bc\uff0c Java\uff0c C\/C++\uff0c JavaScript\uff0c PHP\uff0c HTML\uff0c CSS\uff0c MySQL\uff0c mobile\uff0c Android\uff0c \u52d5\u6f2b\uff0c Python\uff0c teacher\uff0c \u88dc\u7fd2\uff0c \u96fb\u8166\u88dc\u7fd2 \u8cc7\u8a0a, \u7535\u5b50\u8ba1\u7b97\u673a, IT ,Game, apple, movie, Computer,student,Java,\u6559\u80b2, ,\u5b66\u751f, \u5b66\u4e60, learn, \u6559\u5b66,  Android, apple,anime, animation, \u4fe1\u606f\u6280\u672f, \u7a0b\u5e8f\u8bbe\u8ba1, \u79fb\u52a8\u7535\u8bdd, \u8cc7\u8a0a\u79d1\u6280,Game, Jeu, Juego,Call Of Duty ,\u4f7f\u547d\u53ec\u559a , \u6e38\u620f, \u7535\u5b50\u6e38\u620f,, \u591a\u4eba\u7535\u5b50\u6e38\u620f, \u7f51\u7edc\u6e38\u620f\uff0conline\uff0conline game, \u624b\u673a\u6e38\u620f, mobile \\\"><\/p>\n<p><span>Debugging in GDB: Create custom stack winders<\/span><\/p>\n<p>In this article, we will walk through the process of creating a custom stack unwinder for the GNU Project Debugger (GDB) using GDB&#8217;s <a href=\"https:\/\/developers.redhat.com\/topics\/python\">Python<\/a> API. We&#8217;ll first explore when writing such an unwinder might be necessary, then create a small example application that demonstrates a need for a custom unwinder before finally writing a custom unwinder for our application inside the debugger.<\/p>\n<p>By the end of this tutorial, you&#8217;ll be able to use our custom stack unwinder to allow GDB to create a full backtrace for our application.<\/p>\n<h2>What is an unwinder?<\/h2>\n<p>An unwinder is how GDB figures out the call stack of an inferior, for example, GDB&#8217;s <code>backtrace<\/code> command:<\/p>\n<pre>\n<code>Breakpoint 1, woof () at stack.c:4 4 return 0; \n\n(gdb) backtrace\n#0 woof () at stack.c:4\n#1 0x000000000040111f in bar () at stack.c:10\n#2 0x000000000040112f in foo () at stack.c:16\n#3 0x000000000040113f in main () at stack.c:22 \n(gdb)<\/code><\/pre>\n<p>Figuring out frame #0 is easy; the current program counter (<code>$pc<\/code>) value tells GDB which function the inferior is currently in. But to figure out the other frames, GDB needs to read information from the inferior&#8217;s registers and memory. The unwinder is the component of GDB that performs this task.<\/p>\n<p>Having an understanding of the inferior&#8217;s frames isn&#8217;t just used for displaying the backtrace, though; commands like <code>next<\/code> and <code>finish<\/code> also need an accurate understanding of the stack frames in order to function properly.<\/p>\n<p>Any time GDB needs information about a frame beyond #0, an unwinder will have been used.<\/p>\n<h2>What is a custom unwinder?<\/h2>\n<p>GDB already has multiple built-in unwinders for all the major architectures GDB supports. By far, the most common unwinder will be the DWARF unwinder, which reads the DWARF debug information and uses it to unwind the stack for GDB.<\/p>\n<p>But not all functions are compiled with debug information. When GDB finds a function without DWARF debug information, it falls back to a built-in prologue analysis unwinder.<\/p>\n<p>The prologue analysis unwinder disassembles the instructions at the start of a function and uses this information, combined with an understanding of the architecture&#8217;s ABI, to provide unwind information. For many functions, the prologue analysis unwinder will do a reasonable job. Still, there&#8217;s a limit to how smart the prologue analysis unwinder can be, and GDB can never expect to handle every function this way.<\/p>\n<p>And this is where the Python unwinder API comes in. Using this API, it is possible to write Python code that will be loaded into GDB. This code can then &#8220;claim&#8221; frames for which GDB is otherwise unable to unwind correctly, and the Python code can instead be used to provide the unwind information to GDB.<\/p>\n<h2>Building an example use case<\/h2>\n<p>In most well-written applications, very few functions will need the support of a custom unwinder. The sort of functions that GDB will struggle with are those that do unexpected things with the underlying machine state; for example, functions that manipulate the stack in unexpected ways are likely to confuse GDB.<\/p>\n<p>The example application we&#8217;re going to write does just that: it allocates a second stack and uses a small assembler function to switch to, and run a function on, the new stack.<\/p>\n<p>GDB will have no problem unwinding the standard C frames, but the assembler function, which changes the stack, is going to confuse GDB, and initially, we will be unable to obtain a <code>backtrace<\/code> through this function.<\/p>\n<p>Of course, writing in assembly language means this application will only work for one architecture, in this case, x86-64, and the unwinder we eventually write will also be tied to this one architecture. This is perfectly normal; unwinders are dealing with machine registers, so it is expected that an unwinder will only apply to a single architecture.<\/p>\n<p>The demonstration application is split into two files, first, we have <code>demo.c<\/code>:<\/p>\n<pre>\n<code class=\"language-cpp\">#include <stdio.h>\n#include <sys\/mman.h>\n#include <unistd.h>\n#include <stdlib.h>\n\n\/* This function is in our assembly file.  *\/\nextern void run_on_new_stack (void *stack, void (*) (void));\n\n\/* Return pointer to the top of a new stack.  *\/\nstatic void *\nallocate_new_stack (void)\n{\n  int pagesz = getpagesize ();\n  void *ptr = mmap (NULL, pagesz, PROT_READ | PROT_WRITE,\n                \tMAP_ANONYMOUS | MAP_PRIVATE, -1, 0);\n  if (ptr == MAP_FAILED)\n\tabort ();\n  return ptr + pagesz;\n}\n\n\/* A function to run on the alternative stack.  *\/\nstatic void\nfunc (void)\n{\n  printf (\"Hello world\\n\");\n}\n\n\/* Allocate a new stack.  Run a function on the new stack.  *\/\nint\nmain (void)\n{\n  void *new_stack = allocate_new_stack ();\n  run_on_new_stack (new_stack, func);\n  return 0;\n}<\/code><\/pre>\n<p>Then we have <code>runon.S<\/code>:<\/p>\n<pre>\n<code>    \t.global run_on_new_stack\nrun_on_new_stack:\n    \t\/* Incoming arguments:\n\n       \t%rdi    - top of new stack pointer,\n       \t%rsi - function to call.\n\n       \tStore previous %rbp and %rsp to the new stack.\n       \tSet %rbp and $rsp to point to the new stack.\n       \tCall the function in %rsi.  *\/\n    \tmov \t%rbp, -8(%rdi)\n    \tmov \t%rsp, -16(%rdi)\n\n    \tadd \t$-16, %rdi\n\n    \tmov \t%rdi, %rbp\n    \tmov \t%rdi, %rsp\n\n    \tcallq   *%rsi\n\n    \tmovq \t0(%rbp), %rsp\n    \tmovq \t8(%rbp), %rbp\n\n    \tret\n\n    \t.size run_on_new_stack, . - run_on_new_stack\n    \t.type run_on_new_stack, @function\n<\/code><\/pre>\n<p>Finally, compile the application like this:<\/p>\n<pre>\n<code>gcc -g3 -O0 -Wall -Werror -o demo demo.c runon.S<\/code><\/pre>\n<p>Now let&#8217;s see how GDB handles stack unwinding without any additional support. For this, I&#8217;m using GDB 13.1:<\/p>\n<pre>\n<code>$ gdb -q demo\nReading symbols from demo...\n(gdb) break func\nBreakpoint 1 at 0x4011b1: file demo.c, line 25.\n(gdb) run\nStarting program: \/tmp\/demo\n\nBreakpoint 1, func () at demo.c:25\n25      printf (\"Hello world\\n\");\n(gdb) backtrace\n#0  func () at demo.c:25\n#1  0x00000000004011fb in run_on_new_stack () at runon.S:19\n#2  0x00007fffffffad68 in ?? ()\n#3  0x00007fffffffad80 in ?? ()\n#4  0x0000000000000000 in ?? ()\n(gdb)<\/code><\/pre>\n<p>As you can see, GDB can unwind from <code>func<\/code> just fine; after all, that is a &#8220;normal&#8221; function compiled with debug information. But GDB is unable to figure out how to unwind from <code>run_on_new_stack<\/code>.<\/p>\n<h3>What our application is actually doing<\/h3>\n<p>Before we can write a custom unwinder in Python, we need to make sure we fully understand what the demonstration application is actually doing.<\/p>\n<p>We have three frames: <code>main<\/code>, <code>run_on_new_stack<\/code>, and <code>func<\/code>.<\/p>\n<p>In <code>main<\/code>, just before we call <code>run_on_new_stack<\/code>, the application\u2019s stack looks like Figure 1.<\/p>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_01_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_01_0.png?itok=qh8NGQuG\" width=\"532\" height=\"397\" alt=\"Stack in main, just before run_on_new_stack is called.\" typeof=\"foaf:Image\" \/><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 1: Stack in main, just before run_on_new_stack is called.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<p>The register <code>%rbp<\/code>, sometimes known as the frame pointer, points to the top of the frame for <code>main<\/code>, while <code>%rsp<\/code>, otherwise known as the stack pointer, points to the last valid address of the frame for <code>main<\/code>.<\/p>\n<p>When we call from <code>main<\/code> to <code>run_on_new_stack<\/code>, the return address within <code>main<\/code> is pushed onto the stack and <code>%rsp<\/code> is updated. The stack now looks like Figure 2.<\/p>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_02_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_02_0.png?itok=VAH8dv9U\" width=\"532\" height=\"454\" alt=\"State of the stack upon entry to run_on_new_stack.\" typeof=\"foaf:Image\" \/><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 2: State of the stack upon entry to run_on_new_stack.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<p>In <code>main<\/code>, we also allocated a new stack, and this was passed through as the first function argument to <code>run_on_new_stack<\/code>. As such, register <code>%rdi<\/code> points at an address just above the new stack, like this (Figure 3).<\/p>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_03_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_03_0.png?itok=MiI5PIb6\" width=\"310\" height=\"397\" alt=\"Visualisation of the new, empty stack.\" typeof=\"foaf:Image\" \/><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 3: Visualisation of the new, empty stack.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<p>Within <code>run_on_new_stack<\/code> we switch over to the new stack. The return address within <code>main<\/code> is left on the original stack, and the pointers (<code>%rbp<\/code> and <code>%rsp<\/code>) to the original stack are backed up on the new stack, and then updated to point at the new stack. We then call <code>func<\/code>, which will push the return address within <code>run_on_new_stack<\/code> onto the new stack. Once we are in <code>func<\/code>, the state of the two stacks is now as shown in Figures 4 and 5.<\/p>\n<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n<tbody>\n<tr>\n<td>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_04_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_04_0.png?itok=gstn156K\" width=\"443\" height=\"397\" alt=\"Layout of the original stack once run_on_new_stack has switched to the new stack.\" typeof=\"foaf:Image\" \/><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 4: Layout of the original stack once run_on_new_stack has switched to the new stack.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<\/td>\n<td>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_05_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_05_0.png?itok=lK6M13ca\" width=\"532\" height=\"454\" alt=\"Layout of new stack.\" typeof=\"foaf:Image\" \/><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 5: Layout of new stack.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>When unwinding, GDB doesn&#8217;t understand how to use the information on the new stack to find the original stack, and so the <code>backtrace<\/code> is incomplete. This is the problem that our custom unwinder will solve for us.<\/p>\n<h3>Starting our custom unwinder<\/h3>\n<p>The custom unwinder will be written as a Python script in the file <code>runon-unwind.py<\/code>, which we can then source in GDB to provide the extra functionality.<\/p>\n<p>In GDB&#8217;s Python API, an unwinder is an object that implements the <code>__call__<\/code> method. GDB will call each unwinder object for every frame; the unwinder should return <code>None<\/code> if the unwinder doesn&#8217;t handle the frame or return a <code>gdb.UnwindInfo<\/code> object if the unwinder wishes to take responsibility for the frame.<\/p>\n<p>Let&#8217;s start by writing an empty unwinder that doesn&#8217;t claim any frames:<\/p>\n<pre>\n<code class=\"language-python\">from gdb.unwinder import Unwinder\n\n\nclass runto_unwinder(Unwinder):\n    def __init__(self):\n        super().__init__(\"runto_unwinder\")\n\n    def __call__(self, pending_frame):\n        return None\n\n\ngdb.unwinder.register_unwinder(None, runto_unwinder(), replace=True)<\/code><\/pre>\n<p>The last line of this file is responsible for registering the new unwinder with GDB. The first argument <code>None<\/code> tells GDB to register this unwinder in the global scope, but it is also possible to register an unwinder for a specific object file or a specific program space. We&#8217;ll not cover these cases in this tutorial, but the <a href=\"https:\/\/sourceware.org\/gdb\/current\/onlinedocs\/gdb.html\/Unwinding-Frames-in-Python.html\">GDB documentation<\/a> has more details.<\/p>\n<p>The second argument to <code>register_unwinder<\/code> is our new unwinder object. We&#8217;ll discuss this more below.<\/p>\n<p>The final argument <code>replace=True<\/code> indicates that this new unwinder should replace any existing unwinder with the same name. This is useful when developing the unwinder as we can adjust our script and re-source it from GDB; the updated unwinder will then replace the existing one.<\/p>\n<p>In our unwinder object <code>runto_unwinder<\/code>, the constructor just calls the parent constructor and passes in a name for our unwinder. The name can be used within GDB to disable and enable the unwinder using the <code>disable unwinder<\/code> and <code>enable unwinder<\/code> commands, respectively. There is also <code>info unwinder<\/code> which lists all the registered Python unwinders.<\/p>\n<p>Our unwinder object also implements the required <code>__call__<\/code> method. This method is passed a <code>gdb.PendingFrame<\/code> object in <code>pending_frame<\/code>. This pending frame describes the frame that is searching for an unwinder. We must examine this object and decide whether this unwinder applies to this pending frame. By returning <code>None<\/code>, our unwinder is currently telling GDB that we don&#8217;t wish to claim <code>pending_frame<\/code>, our unwinder as it currently stands will not claim any frames, but we can start to address that next.<\/p>\n<h3>Identifying frames to claim<\/h3>\n<p>The first task our new unwinder needs to do is to decide which frame, or frames, should be claimed and which should not be claimed. Any frames not claimed by our unwinder will be offered to any other registered unwinders and will then be offered to GDB&#8217;s built-in unwinders.<\/p>\n<p>The easiest way to decide if we should claim a frame or not is to compare the program-counter address within the frame to the address range of the function we&#8217;re claiming for\u2014in this case,\u00a0<code>run_on_new_stack<\/code>. We can easily find the program-counter address for the frame by reading the <code>$pc<\/code> register. This is done using the <code>read_register<\/code> method of the <code>gdb.PendingFrame<\/code> class.<\/p>\n<p>Having read <code>$pc<\/code>, we need an address range to compare against. For that, we will make use of GDB&#8217;s disassembler. We will disassemble <code>run_on_new_stack<\/code> and extract the address of each instruction. We can then use the first and last addresses as the lower and upper bounds that our unwinder should claim.<\/p>\n<p>Update <code>runon-unwinder.py<\/code> like this:<\/p>\n<pre>\n<code class=\"language-python\">from gdb.unwinder import Unwinder\n\n_unwind_analysis = None\n\n\ndef analyze():\n    global _unwind_analysis\n    # Disassemble the run_on_new_stack function.\n    disasm = gdb.execute(\"disassemble run_on_new_stack\", False, True)\n    # Discard the first and last lines, these don't contain\n    # disassembled instructions, and are of no interest.\n    disasm = disasm.splitlines()[1:-1]\n    # Extract the address of each instruction, and store these\n    # addresses into the global _unwind_analysis list.\n    disasm = [int(l.lstrip().split()[0], 16) for l in disasm]\n    _unwind_analysis = disasm\n\n\nclass runto_unwinder(Unwinder):\n    def __init__(self):\n        super().__init__(\"runto_unwinder\")\n\n    def __call__(self, pending_frame):\n\n        # Analyze the function we're going to unwind.\n        global _unwind_analysis\n        if _unwind_analysis is None:\n            analyze()\n\n        # If this is not a frame we handle then return None.\n        pc = pending_frame.read_register(\"pc\")\n        if pc < _unwind_analysis[0] or pc > _unwind_analysis[-1]:\n            return None\n\n        print(f\"Found a frame we can handle at: {pc}\")\n        return None\n\n\ngdb.unwinder.register_unwinder(None, runto_unwinder(), replace=True)<\/code><\/pre>\n<p>The new <code>analyze<\/code> function disassembles <code>run_on_new_stack<\/code> and stores the address of each instruction in the global <code>_unwind_analysis<\/code> list.<\/p>\n<p>In <code>runto_unwinder.__call__<\/code> we initialize <code>_unwind_analysis<\/code> by calling <code>analyze<\/code> once. We read <code>$pc<\/code> by calling <code>pending_frame.read_register<\/code>, and then we compare <code>pc<\/code> to the first and last addresses in <code>_unwind_analysis<\/code>. If the frame&#8217;s program-counter is outside of the accepted range, then we return <code>None<\/code>; this indicates to GDB that we don&#8217;t wish to claim this frame.<\/p>\n<p>If the frame&#8217;s program-counter is within the range of <code>run_on_new_stack<\/code>, then we print a message, and, for now, also return <code>None<\/code>\u2014don&#8217;t worry, though, we&#8217;ll soon be doing more than returning <code>None<\/code> here, but right now, let&#8217;s test our code.<\/p>\n<p>Using the same demonstration application as before, here&#8217;s an example GDB session:<\/p>\n<pre>\n<code>$ gdb -q demo\nReading symbols from demo...\n(gdb) break func\nBreakpoint 1 at 0x4011b1: file demo.c, line 25.\n(gdb) run\nStarting program: \/tmp\/demo\n\nBreakpoint 1, func () at demo.c:25\n25      printf (\"Hello world\\n\");\n(gdb) source runto-unwind.py\n(gdb) backtrace\nFound a frame we can handle at: 0x4011fb <run_on_new_stack+20>\n#0  func () at demo.c:25\n#1  0x00000000004011fb in run_on_new_stack () at runon.S:19\n#2  0x00007fffffffad38 in ?? ()\n#3  0x00007fffffffad50 in ?? ()\n#4  0x0000000000000000 in ?? ()\n(gdb)<\/code><\/pre>\n<p>Notice the line: <code>Found a frame we can handle at: 0x4011fb <run_on_new_stack+20><\/code>. Don&#8217;t worry if the addresses you see are different; what&#8217;s important is that the message is printed\u2014and printed just once. This indicates that our unwinder has identified a single frame it wishes to claim. The address from that line, <code>0x4011fb<\/code>, matches the address from frame #1, the <code>run_on_new_stack<\/code> frame; this shows that the correct frame was claimed.<\/p>\n<h3>A detour into frame-ids<\/h3>\n<p>The next step is to update the <code>__call__<\/code> method to return a value that indicates the frame has been claimed by this unwinder. However, in order to claim the frame, we must provide a frame-id for the frame.<\/p>\n<p>A frame-id is a unique identifier generated by the unwinder that must be unique for each stack frame but the same for every address within a particular invocation of a function.<\/p>\n<p>Imagine the case where GDB is stepping through a function. After each step, GDB needs to recognize if it is still in the same frame or not. After each step, the unwinder will be used to identify the frame and generate the frame-id again. So long as the generated frame-id is always the same, GDB will understand it is still in the same frame.<\/p>\n<p>Within GDB, frame-ids are a tuple of stack-pointer and code-pointer addresses. Often unwinders use the stack address at entry to the function (typically called the frame base address), and the program address for the function&#8217;s first instruction.<\/p>\n<p>Within GDB&#8217;s Python API, a frame-id is represented by any object that has the <code>sp<\/code> and <code>pc<\/code> attributes. These attributes should contain <code>gdb.Value<\/code> objects representing their respective addresses.<\/p>\n<h3>Creating a frame-ID and UnwindInfo object<\/h3>\n<p>Now that we know about frame-ids, let&#8217;s dive in and update our unwinder. We&#8217;ll discuss these changes afterward. Update <code>runto-unwind.py<\/code> as follows:<\/p>\n<pre>\n<code class=\"language-python\">from gdb.unwinder import Unwinder\n\n_unwind_analysis = None\n\n\ndef analyze():\n    global _unwind_analysis\n    # Disassemble the run_on_new_stack function.\n    disasm = gdb.execute(\"disassemble run_on_new_stack\", False, True)\n    # Discard the first and last lines, these don't contain\n    # disassembled instructions, and are of no interest.\n    disasm = disasm.splitlines()[1:-1]\n    # Extract the address of each instruction, and store these\n    # addresses into the global _unwind_analysis list.\n    disasm = [int(l.lstrip().split()[0], 16) for l in disasm]\n    _unwind_analysis = disasm\n\n\nclass FrameID:\n    def __init__(self, sp, pc):\n        self.sp = sp\n        self.pc = pc\n\n\nclass runto_unwinder(Unwinder):\n    def __init__(self):\n        super().__init__(\"runto_unwinder\")\n\n    def __call__(self, pending_frame):\n\n        # Analyze the function we're going to unwind.\n        global _unwind_analysis\n        if _unwind_analysis is None:\n            analyze()\n\n        # If this is not a frame we handle then return None.\n        pc = pending_frame.read_register(\"pc\")\n        if pc < _unwind_analysis[0] or pc > _unwind_analysis[-1]:\n            return None\n\n        # Create a frame id that will remain consistent throughout\n        # the frame, no matter what $pc we stop at.  We use the $sp\n        # value for the previous frame (this was our $sp on frame\n        # entry), and we use the $pc for the start of the function.\n        #\n        # For the first four and last two instructions, the previous\n        # $sp value can be found in the %rsp register.\n        #\n        # For the fifth and sixth instructions we need to fetch the\n        # previous $sp value from the original stack.\n        rsp = pending_frame.read_register(\"rsp\")\n        if pc < _unwind_analysis[5] or pc > _unwind_analysis[6]:\n            frame_sp = rsp\n        else:\n            frame_sp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" % rsp)\n        func_start = gdb.Value(_unwind_analysis[0])\n        frame_id = FrameID(frame_sp, func_start)\n\n        # Create the unwind_info cache object which holds our unwound\n        # registers.\n        unwind_info = pending_frame.create_unwind_info(frame_id)\n\n        print(f\"Found a frame we can handle at: {pc}\")\n        return None\n\n\ngdb.unwinder.register_unwinder(None, runto_unwinder(), replace=True)<\/code><\/pre>\n<p>Currently, GDB doesn&#8217;t include any helper classes that can be used to represent a frame-id, so we need to define our own \u2013 <code>FrameID<\/code>. The only requirements are that this class has the <code>sp<\/code> and <code>pc<\/code> attributes.<\/p>\n<p>Within the <code>__call__<\/code> method we use the first address of <code>run_on_new_stack<\/code> as the program-counter value for the frame-id. This is done with this line:<\/p>\n<pre>\n<code class=\"language-python\">        func_start = gdb.Value(_unwind_analysis[0])<\/code><\/pre>\n<p>For the stack-pointer address of the frame-id, we need to be smarter. When we first enter <code>run_on_new_stack<\/code>, the previous stack-pointer value is still present in <code>%rsp<\/code>, but within <code>run_on_new_stack<\/code>, the <code>%rsp<\/code> register is stored to the new stack and a new value loaded into <code>%rsp<\/code>.<\/p>\n<p>To handle these two cases, we use the following block of code:<\/p>\n<pre>\n<code class=\"language-python\">        if pc < _unwind_analysis[5] or pc > _unwind_analysis[6]:\n            frame_sp = rsp\n        else:\n            frame_sp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" \n                                          % rsp)<\/code><\/pre>\n<p>We choose between the two possible paths based on the current location within the function. The addresses <code>_unwind_analysis[5]<\/code> and <code>_unwind_analysis[6]<\/code> were chosen by reviewing the instruction disassembly for <code>run_on_new_stack<\/code>. A good exercise would be to disassemble the function and convince yourself that the above choices are correct.<\/p>\n<p>We can now create an instance of our <code>FrameID<\/code> class and use this instance to create a <code>gdb.UnwindInfo<\/code> object with these lines:<\/p>\n<pre>\n<code class=\"language-python\">        frame_id = FrameID(frame_sp, func_start)\n\n        # Create the unwind_info cache object which holds our unwound\n        # registers.\t \n        unwind_info = pending_frame.create_unwind_info(frame_id)<\/code><\/pre>\n<p>The <code>gdb.UnwindInfo<\/code> class is the last piece of the unwinder process. We will store unwound register values into our <code>unwind_info<\/code> object and return this to GDB in order to claim this frame. However, we&#8217;re not there just yet\u2014for now, we&#8217;re still printing a debug message and returning <code>None<\/code>.<\/p>\n<h3>Adding unwound register values<\/h3>\n<p>Having decided to claim this frame, and having created a <code>gdb.UnwindInfo<\/code> object, we need to store some unwound register values in our new <code>unwind_info<\/code> object.<\/p>\n<p>The unwound value of a register is the value a register had in the previous frame.<\/p>\n<p>Locating the previous register values will involve understanding the assembler code for the function being unwound. You don&#8217;t need to provide previous values for every register; in some cases, the previous value of a register will not be available at all, in which case nothing can be done.<\/p>\n<p>To keep the complexity of this example down, we are only going to provide previous values for 3 registers, the program counter, <code>%rsp<\/code>, and <code>%rbp<\/code>. These registers are enough to allow GDB to build a complete backtrace on x86-64. Once you&#8217;ve seen how these registers are supported, extending the example to support other registers as needed should be easy enough.<\/p>\n<p>As before, let&#8217;s just update <code>runon-unwind.py<\/code>, and discuss the changes afterwards:<\/p>\n<pre>\n<code class=\"language-python\">from gdb.unwinder import Unwinder\n\n_unwind_analysis = None\n\n\ndef analyze():\n    global _unwind_analysis\n    # Disassemble the run_on_new_stack function.\n    disasm = gdb.execute(\"disassemble run_on_new_stack\", False, True)\n    # Discard the first and last lines, these don't contain\n    # disassembled instructions, and are of no interest.\n    disasm = disasm.splitlines()[1:-1]\n    # Extract the address of each instruction, and store these\n    # addresses into the global _unwind_analysis list.\n    disasm = [int(l.lstrip().split()[0], 16) for l in disasm]\n    _unwind_analysis = disasm\n\n\nclass FrameID:\n    def __init__(self, sp, pc):\n        self.sp = sp\n        self.pc = pc\n\n\nclass runto_unwinder(Unwinder):\n    def __init__(self):\n        super().__init__(\"runto_unwinder\")\n\n    def __call__(self, pending_frame):\n\n        # Analyze the function we're going to unwind.\n        global _unwind_analysis\n        if _unwind_analysis is None:\n            analyze()\n\n        # If this is not a frame we handle then return None.\n        pc = pending_frame.read_register(\"pc\")\n        if pc < _unwind_analysis[0] or pc > _unwind_analysis[-1]:\n            return None\n\n        # Create a frame id that will remain consistent throughout the\n        # frame, no matter what $pc we stop at.  We use the $sp value\n        # for the previous frame (this was our $sp on frame entry),\n        # and we use the $pc for the start of the function.\n        #\n        # For the first four and last two instructions, the previous\n        # $sp value can be found in the %rsp register.\n        #\n        # For the fifth and sixth instructions we need to fetch the\n        # previous $sp value from the original stack.\n        rsp = pending_frame.read_register(\"rsp\")\n        if pc < _unwind_analysis[5] or pc > _unwind_analysis[6]:\n            frame_sp = rsp\n        else:\n            frame_sp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" % rsp)\n        func_start = gdb.Value(_unwind_analysis[0])\n        frame_id = FrameID(frame_sp, func_start)\n\n        # Create the unwind_info cache object which holds our unwound\n        # registers.\n        unwind_info = pending_frame.create_unwind_info(frame_id)\n\n        # Calculate the previous register values.  Select the correct\n        # previous value for $rbp based on where we are in the\n        # function.\n        if pc < _unwind_analysis[4] or pc > _unwind_analysis[7]:\n            prev_rbp = pending_frame.read_register(\"rbp\")\n        else:\n            prev_rbp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" % (rsp + 8))\n\n        # We use the previous $sp value in our frame-id, which is handy!\n        prev_rsp = frame_sp\n\n        # The previous $pc is always on the original (incoming) stack.\n        prev_pc = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" % (prev_rsp))\n\n        # And store the previous values into our cache.\n        unwind_info.add_saved_register(\"rsp\", prev_rsp)\n        unwind_info.add_saved_register(\"rbp\", prev_rbp)\n        unwind_info.add_saved_register(\"pc\", prev_pc)\n\n        # Return the cache for GDB to use.\n        return unwind_info\n\n\ngdb.unwinder.register_unwinder(None, runto_unwinder(), replace=True)<\/code><\/pre>\n<p>The most important part of this new version are the three calls to <code>unwind_info.add_saved_register<\/code>; this is how we record the unwound register values. The first argument to these calls is the name of the register we are recording, and the second argument is the value that register had in the previous frame.<\/p>\n<p>The three registers we record are <code>pc<\/code>, <code>rsp<\/code>, and <code>rbp<\/code>. Figuring out the previous value for the first two registers is pretty easy. We already have the previous <code>rsp<\/code> value, remember, this is what we used for our frame-id so that we can reuse that value here.<\/p>\n<p>Recall from our earlier stack diagrams; the return address in <code>main<\/code> was the last thing stored on the original stack, this is what the previous stack-pointer points at, so we can load the return address with this line:<\/p>\n<pre>\n<code class=\"language-python\">        prev_pc = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" \n                                     % (prev_rsp))<\/code><\/pre>\n<p>And this just leaves the previous <code>rbp<\/code> value. Just like we found the previous <code>rsp<\/code> value earlier, the current instruction within <code>run_on_new_stack<\/code> will determine the location of the previous <code>rbp<\/code> value. Initially the previous value is in the <code>rbp<\/code> register, but we store this previous value to the new stack before calling <code>func<\/code>. And so, to find the correct previous value, we need to switch based on the program-counter value, which we do with these lines:<\/p>\n<pre>\n<code class=\"language-python\">        if pc < _unwind_analysis[4] or pc > _unwind_analysis[7]:\n            prev_rbp = pending_frame.read_register(\"rbp\")\n        else:\n            prev_rbp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" \n                                          % (rsp + 8))<\/code><\/pre>\n<p>The last update is to remove the debug message that we have been printing until now, and instead of returning <code>None<\/code>, return our <code>gdb.UnwindInfo<\/code> object <code>unwind_info<\/code>. This tells GDB that our unwinder has claimed this frame. GDB will use the previous register values stored within <code>unwind_info<\/code> when it needs to unwind through this frame.<\/p>\n<p>So, for the last time, let&#8217;s try our unwinder in GDB:<\/p>\n<pre>\n<code>$ gdb -q demo\nReading symbols from demo...\n(gdb) break func\nBreakpoint 1 at 0x4011b1: file demo.c, line 25.\n(gdb) run\nStarting program: \/tmp\/demo\n\nBreakpoint 1, func () at demo.c:25\n25      printf (\"Hello world\\n\");\n(gdb) source runon-unwind.py\n(gdb) backtrace\n#0  func () at demo.c:25\n#1  0x00000000004011fb in run_on_new_stack () at runon.S:19\n#2  0x00000000004011e0 in main () at demo.c:33\n(gdb)<\/code><\/pre>\n<p>And success! We can now unwind through <code>run_on_new_stack<\/code> back to <code>main<\/code>.<\/p>\n<h3>Summary and conclusions<\/h3>\n<p>Writing custom stack unwinders is not trivial; it requires a good understanding of the function being unwound and the architecture the unwinder is being written for. There is more to GDB&#8217;s unwinder API than has been discussed in this brief introduction. The full details can all be found in the <a href=\"https:\/\/sourceware.org\/gdb\/current\/onlinedocs\/gdb.html\/Unwinding-Frames-in-Python.html\">documentation<\/a>.<\/p>\n<p><span><span lang=\"\" about=\"https:\/\/developers.redhat.com\/user\/746341\" typeof=\"schema:Person\" property=\"schema:name\" datatype=\"\" xml:lang=\"\">aburgess@redhat.com<\/span><\/span><br \/>\n<span>Mon, 06\/19\/2023 &#8211; 07:00<\/span><br \/>\n<a href=\"https:\/\/developers.redhat.com\/author\/andrew-burgess\" hreflang=\"en\">Andrew Burgess<\/a><\/p>\n\n<p class=\"syndicated-attribution\"><figure class= \\\"wp-block-image alignnone \\\"><img src= \\\"http:\/\/itteacheritfreelance.hk\/test\/wordpress\/wp-content\/uploads\/2016\/05\/logo2-2.png\\\" alt=\\\"IT\u96fb\u8166\u88dc\u7fd2 java\u88dc\u7fd2 \u70ba\u5927\u5bb6\u914d\u5c0d\u96fb\u8166\u88dc\u7fd2,IT freelance, \u79c1\u4eba\u8001\u5e2b, PHP\u88dc\u7fd2,CSS\u88dc\u7fd2,XML,Java\u88dc\u7fd2,MySQL\u88dc\u7fd2,graphic design\u88dc\u7fd2,\u4e2d\u5c0f\u5b78ICT\u88dc\u7fd2,\u4e00\u5c0d\u4e00\u79c1\u4eba\u88dc\u7fd2\u548cFreelance\u81ea\u7531\u5de5\u4f5c\u914d\u5c0d\u3002\\\"\/><figcaption>\u7acb\u523b\u8a3b\u518a\u53ca\u5831\u540d\u96fb\u8166\u88dc\u7fd2\u8ab2\u7a0b\u5427!<\/figcaption><\/figure>\r\n<\/br>Find A Teacher Form:\r\n<\/br>https:\/\/docs.google.com\/forms\/d\/1vREBnX5n262umf4wU5U2pyTwvk9O-JrAgblA-wH9GFQ\/viewform?edit_requested=true#responses\r\n<\/br><\/br>Email:\r\n<\/br>public1989two@gmail.com<br><br><br><br><br><br><br>\r\n<a href=www.itsec.hk style=color:#FFFFFF;>www.itsec.hk<\/a><br>\r\n<a href=\\\"www.itsec.vip\\\" style=color:#FFFFFF;>www.itsec.vip<\/a><br>\r\n<a href=\\\"www.itseceu.uk\\\" style=color:#FFFFFF;>www.itseceu.uk<\/a><br><\/p>","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p><span>Debugging in GDB: Create custom stack winders<\/span><\/p>\n<p>In this article, we will walk through the process of creating a custom stack unwinder for the GNU Project Debugger (GDB) using GDB&#8217;s <a href=\"https:\/\/developers.redhat.com\/topics\/python\">Python<\/a> API. We&#8217;ll first explore when writing such an unwinder might be necessary, then create a small example application that demonstrates a need for a custom unwinder before finally writing a custom unwinder for our application inside the debugger.<\/p>\n<p>By the end of this tutorial, you&#8217;ll be able to use our custom stack unwinder to allow GDB to create a full backtrace for our application.<\/p>\n<h2>What is an unwinder?<\/h2>\n<p>An unwinder is how GDB figures out the call stack of an inferior, for example, GDB&#8217;s <code>backtrace<\/code> command:<\/p>\n<pre>\n<code>Breakpoint 1, woof () at stack.c:4 4 return 0; \n\n(gdb) backtrace\n#0 woof () at stack.c:4\n#1 0x000000000040111f in bar () at stack.c:10\n#2 0x000000000040112f in foo () at stack.c:16\n#3 0x000000000040113f in main () at stack.c:22 \n(gdb)<\/code><\/pre>\n<p>Figuring out frame #0 is easy; the current program counter (<code>$pc<\/code>) value tells GDB which function the inferior is currently in. But to figure out the other frames, GDB needs to read information from the inferior&#8217;s registers and memory. The unwinder is the component of GDB that performs this task.<\/p>\n<p>Having an understanding of the inferior&#8217;s frames isn&#8217;t just used for displaying the backtrace, though; commands like <code>next<\/code> and <code>finish<\/code> also need an accurate understanding of the stack frames in order to function properly.<\/p>\n<p>Any time GDB needs information about a frame beyond #0, an unwinder will have been used.<\/p>\n<h2>What is a custom unwinder?<\/h2>\n<p>GDB already has multiple built-in unwinders for all the major architectures GDB supports. By far, the most common unwinder will be the DWARF unwinder, which reads the DWARF debug information and uses it to unwind the stack for GDB.<\/p>\n<p>But not all functions are compiled with debug information. When GDB finds a function without DWARF debug information, it falls back to a built-in prologue analysis unwinder.<\/p>\n<p>The prologue analysis unwinder disassembles the instructions at the start of a function and uses this information, combined with an understanding of the architecture&#8217;s ABI, to provide unwind information. For many functions, the prologue analysis unwinder will do a reasonable job. Still, there&#8217;s a limit to how smart the prologue analysis unwinder can be, and GDB can never expect to handle every function this way.<\/p>\n<p>And this is where the Python unwinder API comes in. Using this API, it is possible to write Python code that will be loaded into GDB. This code can then &#8220;claim&#8221; frames for which GDB is otherwise unable to unwind correctly, and the Python code can instead be used to provide the unwind information to GDB.<\/p>\n<h2>Building an example use case<\/h2>\n<p>In most well-written applications, very few functions will need the support of a custom unwinder. The sort of functions that GDB will struggle with are those that do unexpected things with the underlying machine state; for example, functions that manipulate the stack in unexpected ways are likely to confuse GDB.<\/p>\n<p>The example application we&#8217;re going to write does just that: it allocates a second stack and uses a small assembler function to switch to, and run a function on, the new stack.<\/p>\n<p>GDB will have no problem unwinding the standard C frames, but the assembler function, which changes the stack, is going to confuse GDB, and initially, we will be unable to obtain a <code>backtrace<\/code> through this function.<\/p>\n<p>Of course, writing in assembly language means this application will only work for one architecture, in this case, x86-64, and the unwinder we eventually write will also be tied to this one architecture. This is perfectly normal; unwinders are dealing with machine registers, so it is expected that an unwinder will only apply to a single architecture.<\/p>\n<p>The demonstration application is split into two files, first, we have <code>demo.c<\/code>:<\/p>\n<pre>\n<code class=\"language-cpp\">#include <stdio.h>\n#include <sys>\n#include <unistd.h>\n#include <stdlib.h>\n\n\/* This function is in our assembly file.  *\/\nextern void run_on_new_stack (void *stack, void (*) (void));\n\n\/* Return pointer to the top of a new stack.  *\/\nstatic void *\nallocate_new_stack (void)\n{\n  int pagesz = getpagesize ();\n  void *ptr = mmap (NULL, pagesz, PROT_READ | PROT_WRITE,\n                \tMAP_ANONYMOUS | MAP_PRIVATE, -1, 0);\n  if (ptr == MAP_FAILED)\n\tabort ();\n  return ptr + pagesz;\n}\n\n\/* A function to run on the alternative stack.  *\/\nstatic void\nfunc (void)\n{\n  printf (\"Hello world\\n\");\n}\n\n\/* Allocate a new stack.  Run a function on the new stack.  *\/\nint\nmain (void)\n{\n  void *new_stack = allocate_new_stack ();\n  run_on_new_stack (new_stack, func);\n  return 0;\n}<\/stdlib.h><\/unistd.h><\/sys><\/stdio.h><\/code><\/pre>\n<p>Then we have <code>runon.S<\/code>:<\/p>\n<pre>\n<code>    \t.global run_on_new_stack\nrun_on_new_stack:\n    \t\/* Incoming arguments:\n\n       \t%rdi    - top of new stack pointer,\n       \t%rsi - function to call.\n\n       \tStore previous %rbp and %rsp to the new stack.\n       \tSet %rbp and $rsp to point to the new stack.\n       \tCall the function in %rsi.  *\/\n    \tmov \t%rbp, -8(%rdi)\n    \tmov \t%rsp, -16(%rdi)\n\n    \tadd \t$-16, %rdi\n\n    \tmov \t%rdi, %rbp\n    \tmov \t%rdi, %rsp\n\n    \tcallq   *%rsi\n\n    \tmovq \t0(%rbp), %rsp\n    \tmovq \t8(%rbp), %rbp\n\n    \tret\n\n    \t.size run_on_new_stack, . - run_on_new_stack\n    \t.type run_on_new_stack, @function\n<\/code><\/pre>\n<p>Finally, compile the application like this:<\/p>\n<pre>\n<code>gcc -g3 -O0 -Wall -Werror -o demo demo.c runon.S<\/code><\/pre>\n<p>Now let&#8217;s see how GDB handles stack unwinding without any additional support. For this, I&#8217;m using GDB 13.1:<\/p>\n<pre>\n<code>$ gdb -q demo\nReading symbols from demo...\n(gdb) break func\nBreakpoint 1 at 0x4011b1: file demo.c, line 25.\n(gdb) run\nStarting program: \/tmp\/demo\n\nBreakpoint 1, func () at demo.c:25\n25      printf (\"Hello world\\n\");\n(gdb) backtrace\n#0  func () at demo.c:25\n#1  0x00000000004011fb in run_on_new_stack () at runon.S:19\n#2  0x00007fffffffad68 in ?? ()\n#3  0x00007fffffffad80 in ?? ()\n#4  0x0000000000000000 in ?? ()\n(gdb)<\/code><\/pre>\n<p>As you can see, GDB can unwind from <code>func<\/code> just fine; after all, that is a &#8220;normal&#8221; function compiled with debug information. But GDB is unable to figure out how to unwind from <code>run_on_new_stack<\/code>.<\/p>\n<h3>What our application is actually doing<\/h3>\n<p>Before we can write a custom unwinder in Python, we need to make sure we fully understand what the demonstration application is actually doing.<\/p>\n<p>We have three frames: <code>main<\/code>, <code>run_on_new_stack<\/code>, and <code>func<\/code>.<\/p>\n<p>In <code>main<\/code>, just before we call <code>run_on_new_stack<\/code>, the application\u2019s stack looks like Figure 1.<\/p>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_01_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_01_0.png?itok=qh8NGQuG\" width=\"532\" height=\"397\" alt=\"Stack in main, just before run_on_new_stack is called.\" typeof=\"foaf:Image\"><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 1: Stack in main, just before run_on_new_stack is called.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<p>The register <code>%rbp<\/code>, sometimes known as the frame pointer, points to the top of the frame for <code>main<\/code>, while <code>%rsp<\/code>, otherwise known as the stack pointer, points to the last valid address of the frame for <code>main<\/code>.<\/p>\n<p>When we call from <code>main<\/code> to <code>run_on_new_stack<\/code>, the return address within <code>main<\/code> is pushed onto the stack and <code>%rsp<\/code> is updated. The stack now looks like Figure 2.<\/p>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_02_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_02_0.png?itok=VAH8dv9U\" width=\"532\" height=\"454\" alt=\"State of the stack upon entry to run_on_new_stack.\" typeof=\"foaf:Image\"><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 2: State of the stack upon entry to run_on_new_stack.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<p>In <code>main<\/code>, we also allocated a new stack, and this was passed through as the first function argument to <code>run_on_new_stack<\/code>. As such, register <code>%rdi<\/code> points at an address just above the new stack, like this (Figure 3).<\/p>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_03_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_03_0.png?itok=MiI5PIb6\" width=\"310\" height=\"397\" alt=\"Visualisation of the new, empty stack.\" typeof=\"foaf:Image\"><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 3: Visualisation of the new, empty stack.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<p>Within <code>run_on_new_stack<\/code> we switch over to the new stack. The return address within <code>main<\/code> is left on the original stack, and the pointers (<code>%rbp<\/code> and <code>%rsp<\/code>) to the original stack are backed up on the new stack, and then updated to point at the new stack. We then call <code>func<\/code>, which will push the return address within <code>run_on_new_stack<\/code> onto the new stack. Once we are in <code>func<\/code>, the state of the two stacks is now as shown in Figures 4 and 5.<\/p>\n<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n<tbody>\n<tr>\n<td>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_04_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_04_0.png?itok=gstn156K\" width=\"443\" height=\"397\" alt=\"Layout of the original stack once run_on_new_stack has switched to the new stack.\" typeof=\"foaf:Image\"><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 4: Layout of the original stack once run_on_new_stack has switched to the new stack.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<\/td>\n<td>\n<div class=\"rhd-c-figure\">\n<article class=\"align-center media media--type-image media--view-mode-article-content\">\n<div class=\"field field--name-image field--type-image field--label-hidden field__items\">\n  <a href=\"https:\/\/developers.redhat.com\/sites\/default\/files\/stack_05_0.png\" data-featherlight=\"image\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/developers.redhat.com\/sites\/default\/files\/styles\/article_floated\/public\/stack_05_0.png?itok=lK6M13ca\" width=\"532\" height=\"454\" alt=\"Layout of new stack.\" typeof=\"foaf:Image\"><\/a>\n<\/div>\n<div class=\"field field--name-field-caption field--type-string field--label-hidden field__items\">\n<div class=\"rhd-c-caption field__item\">Figure 5: Layout of new stack.<\/div>\n<\/div>\n<\/article>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>When unwinding, GDB doesn&#8217;t understand how to use the information on the new stack to find the original stack, and so the <code>backtrace<\/code> is incomplete. This is the problem that our custom unwinder will solve for us.<\/p>\n<h3>Starting our custom unwinder<\/h3>\n<p>The custom unwinder will be written as a Python script in the file <code>runon-unwind.py<\/code>, which we can then source in GDB to provide the extra functionality.<\/p>\n<p>In GDB&#8217;s Python API, an unwinder is an object that implements the <code>__call__<\/code> method. GDB will call each unwinder object for every frame; the unwinder should return <code>None<\/code> if the unwinder doesn&#8217;t handle the frame or return a <code>gdb.UnwindInfo<\/code> object if the unwinder wishes to take responsibility for the frame.<\/p>\n<p>Let&#8217;s start by writing an empty unwinder that doesn&#8217;t claim any frames:<\/p>\n<pre>\n<code class=\"language-python\">from gdb.unwinder import Unwinder\n\n\nclass runto_unwinder(Unwinder):\n    def __init__(self):\n        super().__init__(\"runto_unwinder\")\n\n    def __call__(self, pending_frame):\n        return None\n\n\ngdb.unwinder.register_unwinder(None, runto_unwinder(), replace=True)<\/code><\/pre>\n<p>The last line of this file is responsible for registering the new unwinder with GDB. The first argument <code>None<\/code> tells GDB to register this unwinder in the global scope, but it is also possible to register an unwinder for a specific object file or a specific program space. We&#8217;ll not cover these cases in this tutorial, but the <a href=\"https:\/\/sourceware.org\/gdb\/current\/onlinedocs\/gdb.html\/Unwinding-Frames-in-Python.html\">GDB documentation<\/a> has more details.<\/p>\n<p>The second argument to <code>register_unwinder<\/code> is our new unwinder object. We&#8217;ll discuss this more below.<\/p>\n<p>The final argument <code>replace=True<\/code> indicates that this new unwinder should replace any existing unwinder with the same name. This is useful when developing the unwinder as we can adjust our script and re-source it from GDB; the updated unwinder will then replace the existing one.<\/p>\n<p>In our unwinder object <code>runto_unwinder<\/code>, the constructor just calls the parent constructor and passes in a name for our unwinder. The name can be used within GDB to disable and enable the unwinder using the <code>disable unwinder<\/code> and <code>enable unwinder<\/code> commands, respectively. There is also <code>info unwinder<\/code> which lists all the registered Python unwinders.<\/p>\n<p>Our unwinder object also implements the required <code>__call__<\/code> method. This method is passed a <code>gdb.PendingFrame<\/code> object in <code>pending_frame<\/code>. This pending frame describes the frame that is searching for an unwinder. We must examine this object and decide whether this unwinder applies to this pending frame. By returning <code>None<\/code>, our unwinder is currently telling GDB that we don&#8217;t wish to claim <code>pending_frame<\/code>, our unwinder as it currently stands will not claim any frames, but we can start to address that next.<\/p>\n<h3>Identifying frames to claim<\/h3>\n<p>The first task our new unwinder needs to do is to decide which frame, or frames, should be claimed and which should not be claimed. Any frames not claimed by our unwinder will be offered to any other registered unwinders and will then be offered to GDB&#8217;s built-in unwinders.<\/p>\n<p>The easiest way to decide if we should claim a frame or not is to compare the program-counter address within the frame to the address range of the function we&#8217;re claiming for\u2014in this case,\u00a0<code>run_on_new_stack<\/code>. We can easily find the program-counter address for the frame by reading the <code>$pc<\/code> register. This is done using the <code>read_register<\/code> method of the <code>gdb.PendingFrame<\/code> class.<\/p>\n<p>Having read <code>$pc<\/code>, we need an address range to compare against. For that, we will make use of GDB&#8217;s disassembler. We will disassemble <code>run_on_new_stack<\/code> and extract the address of each instruction. We can then use the first and last addresses as the lower and upper bounds that our unwinder should claim.<\/p>\n<p>Update <code>runon-unwinder.py<\/code> like this:<\/p>\n<pre>\n<code class=\"language-python\">from gdb.unwinder import Unwinder\n\n_unwind_analysis = None\n\n\ndef analyze():\n    global _unwind_analysis\n    # Disassemble the run_on_new_stack function.\n    disasm = gdb.execute(\"disassemble run_on_new_stack\", False, True)\n    # Discard the first and last lines, these don't contain\n    # disassembled instructions, and are of no interest.\n    disasm = disasm.splitlines()[1:-1]\n    # Extract the address of each instruction, and store these\n    # addresses into the global _unwind_analysis list.\n    disasm = [int(l.lstrip().split()[0], 16) for l in disasm]\n    _unwind_analysis = disasm\n\n\nclass runto_unwinder(Unwinder):\n    def __init__(self):\n        super().__init__(\"runto_unwinder\")\n\n    def __call__(self, pending_frame):\n\n        # Analyze the function we're going to unwind.\n        global _unwind_analysis\n        if _unwind_analysis is None:\n            analyze()\n\n        # If this is not a frame we handle then return None.\n        pc = pending_frame.read_register(\"pc\")\n        if pc  _unwind_analysis[-1]:\n            return None\n\n        print(f\"Found a frame we can handle at: {pc}\")\n        return None\n\n\ngdb.unwinder.register_unwinder(None, runto_unwinder(), replace=True)<\/code><\/pre>\n<p>The new <code>analyze<\/code> function disassembles <code>run_on_new_stack<\/code> and stores the address of each instruction in the global <code>_unwind_analysis<\/code> list.<\/p>\n<p>In <code>runto_unwinder.__call__<\/code> we initialize <code>_unwind_analysis<\/code> by calling <code>analyze<\/code> once. We read <code>$pc<\/code> by calling <code>pending_frame.read_register<\/code>, and then we compare <code>pc<\/code> to the first and last addresses in <code>_unwind_analysis<\/code>. If the frame&#8217;s program-counter is outside of the accepted range, then we return <code>None<\/code>; this indicates to GDB that we don&#8217;t wish to claim this frame.<\/p>\n<p>If the frame&#8217;s program-counter is within the range of <code>run_on_new_stack<\/code>, then we print a message, and, for now, also return <code>None<\/code>\u2014don&#8217;t worry, though, we&#8217;ll soon be doing more than returning <code>None<\/code> here, but right now, let&#8217;s test our code.<\/p>\n<p>Using the same demonstration application as before, here&#8217;s an example GDB session:<\/p>\n<pre>\n<code>$ gdb -q demo\nReading symbols from demo...\n(gdb) break func\nBreakpoint 1 at 0x4011b1: file demo.c, line 25.\n(gdb) run\nStarting program: \/tmp\/demo\n\nBreakpoint 1, func () at demo.c:25\n25      printf (\"Hello world\\n\");\n(gdb) source runto-unwind.py\n(gdb) backtrace\nFound a frame we can handle at: 0x4011fb <run_on_new_stack>\n#0  func () at demo.c:25\n#1  0x00000000004011fb in run_on_new_stack () at runon.S:19\n#2  0x00007fffffffad38 in ?? ()\n#3  0x00007fffffffad50 in ?? ()\n#4  0x0000000000000000 in ?? ()\n(gdb)<\/run_on_new_stack><\/code><\/pre>\n<p>Notice the line: <code>Found a frame we can handle at: 0x4011fb <run_on_new_stack><\/run_on_new_stack><\/code>. Don&#8217;t worry if the addresses you see are different; what&#8217;s important is that the message is printed\u2014and printed just once. This indicates that our unwinder has identified a single frame it wishes to claim. The address from that line, <code>0x4011fb<\/code>, matches the address from frame #1, the <code>run_on_new_stack<\/code> frame; this shows that the correct frame was claimed.<\/p>\n<h3>A detour into frame-ids<\/h3>\n<p>The next step is to update the <code>__call__<\/code> method to return a value that indicates the frame has been claimed by this unwinder. However, in order to claim the frame, we must provide a frame-id for the frame.<\/p>\n<p>A frame-id is a unique identifier generated by the unwinder that must be unique for each stack frame but the same for every address within a particular invocation of a function.<\/p>\n<p>Imagine the case where GDB is stepping through a function. After each step, GDB needs to recognize if it is still in the same frame or not. After each step, the unwinder will be used to identify the frame and generate the frame-id again. So long as the generated frame-id is always the same, GDB will understand it is still in the same frame.<\/p>\n<p>Within GDB, frame-ids are a tuple of stack-pointer and code-pointer addresses. Often unwinders use the stack address at entry to the function (typically called the frame base address), and the program address for the function&#8217;s first instruction.<\/p>\n<p>Within GDB&#8217;s Python API, a frame-id is represented by any object that has the <code>sp<\/code> and <code>pc<\/code> attributes. These attributes should contain <code>gdb.Value<\/code> objects representing their respective addresses.<\/p>\n<h3>Creating a frame-ID and UnwindInfo object<\/h3>\n<p>Now that we know about frame-ids, let&#8217;s dive in and update our unwinder. We&#8217;ll discuss these changes afterward. Update <code>runto-unwind.py<\/code> as follows:<\/p>\n<pre>\n<code class=\"language-python\">from gdb.unwinder import Unwinder\n\n_unwind_analysis = None\n\n\ndef analyze():\n    global _unwind_analysis\n    # Disassemble the run_on_new_stack function.\n    disasm = gdb.execute(\"disassemble run_on_new_stack\", False, True)\n    # Discard the first and last lines, these don't contain\n    # disassembled instructions, and are of no interest.\n    disasm = disasm.splitlines()[1:-1]\n    # Extract the address of each instruction, and store these\n    # addresses into the global _unwind_analysis list.\n    disasm = [int(l.lstrip().split()[0], 16) for l in disasm]\n    _unwind_analysis = disasm\n\n\nclass FrameID:\n    def __init__(self, sp, pc):\n        self.sp = sp\n        self.pc = pc\n\n\nclass runto_unwinder(Unwinder):\n    def __init__(self):\n        super().__init__(\"runto_unwinder\")\n\n    def __call__(self, pending_frame):\n\n        # Analyze the function we're going to unwind.\n        global _unwind_analysis\n        if _unwind_analysis is None:\n            analyze()\n\n        # If this is not a frame we handle then return None.\n        pc = pending_frame.read_register(\"pc\")\n        if pc  _unwind_analysis[-1]:\n            return None\n\n        # Create a frame id that will remain consistent throughout\n        # the frame, no matter what $pc we stop at.  We use the $sp\n        # value for the previous frame (this was our $sp on frame\n        # entry), and we use the $pc for the start of the function.\n        #\n        # For the first four and last two instructions, the previous\n        # $sp value can be found in the %rsp register.\n        #\n        # For the fifth and sixth instructions we need to fetch the\n        # previous $sp value from the original stack.\n        rsp = pending_frame.read_register(\"rsp\")\n        if pc  _unwind_analysis[6]:\n            frame_sp = rsp\n        else:\n            frame_sp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" % rsp)\n        func_start = gdb.Value(_unwind_analysis[0])\n        frame_id = FrameID(frame_sp, func_start)\n\n        # Create the unwind_info cache object which holds our unwound\n        # registers.\n        unwind_info = pending_frame.create_unwind_info(frame_id)\n\n        print(f\"Found a frame we can handle at: {pc}\")\n        return None\n\n\ngdb.unwinder.register_unwinder(None, runto_unwinder(), replace=True)<\/code><\/pre>\n<p>Currently, GDB doesn&#8217;t include any helper classes that can be used to represent a frame-id, so we need to define our own \u2013 <code>FrameID<\/code>. The only requirements are that this class has the <code>sp<\/code> and <code>pc<\/code> attributes.<\/p>\n<p>Within the <code>__call__<\/code> method we use the first address of <code>run_on_new_stack<\/code> as the program-counter value for the frame-id. This is done with this line:<\/p>\n<pre>\n<code class=\"language-python\">        func_start = gdb.Value(_unwind_analysis[0])<\/code><\/pre>\n<p>For the stack-pointer address of the frame-id, we need to be smarter. When we first enter <code>run_on_new_stack<\/code>, the previous stack-pointer value is still present in <code>%rsp<\/code>, but within <code>run_on_new_stack<\/code>, the <code>%rsp<\/code> register is stored to the new stack and a new value loaded into <code>%rsp<\/code>.<\/p>\n<p>To handle these two cases, we use the following block of code:<\/p>\n<pre>\n<code class=\"language-python\">        if pc  _unwind_analysis[6]:\n            frame_sp = rsp\n        else:\n            frame_sp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" \n                                          % rsp)<\/code><\/pre>\n<p>We choose between the two possible paths based on the current location within the function. The addresses <code>_unwind_analysis[5]<\/code> and <code>_unwind_analysis[6]<\/code> were chosen by reviewing the instruction disassembly for <code>run_on_new_stack<\/code>. A good exercise would be to disassemble the function and convince yourself that the above choices are correct.<\/p>\n<p>We can now create an instance of our <code>FrameID<\/code> class and use this instance to create a <code>gdb.UnwindInfo<\/code> object with these lines:<\/p>\n<pre>\n<code class=\"language-python\">        frame_id = FrameID(frame_sp, func_start)\n\n        # Create the unwind_info cache object which holds our unwound\n        # registers.\t \n        unwind_info = pending_frame.create_unwind_info(frame_id)<\/code><\/pre>\n<p>The <code>gdb.UnwindInfo<\/code> class is the last piece of the unwinder process. We will store unwound register values into our <code>unwind_info<\/code> object and return this to GDB in order to claim this frame. However, we&#8217;re not there just yet\u2014for now, we&#8217;re still printing a debug message and returning <code>None<\/code>.<\/p>\n<h3>Adding unwound register values<\/h3>\n<p>Having decided to claim this frame, and having created a <code>gdb.UnwindInfo<\/code> object, we need to store some unwound register values in our new <code>unwind_info<\/code> object.<\/p>\n<p>The unwound value of a register is the value a register had in the previous frame.<\/p>\n<p>Locating the previous register values will involve understanding the assembler code for the function being unwound. You don&#8217;t need to provide previous values for every register; in some cases, the previous value of a register will not be available at all, in which case nothing can be done.<\/p>\n<p>To keep the complexity of this example down, we are only going to provide previous values for 3 registers, the program counter, <code>%rsp<\/code>, and <code>%rbp<\/code>. These registers are enough to allow GDB to build a complete backtrace on x86-64. Once you&#8217;ve seen how these registers are supported, extending the example to support other registers as needed should be easy enough.<\/p>\n<p>As before, let&#8217;s just update <code>runon-unwind.py<\/code>, and discuss the changes afterwards:<\/p>\n<pre>\n<code class=\"language-python\">from gdb.unwinder import Unwinder\n\n_unwind_analysis = None\n\n\ndef analyze():\n    global _unwind_analysis\n    # Disassemble the run_on_new_stack function.\n    disasm = gdb.execute(\"disassemble run_on_new_stack\", False, True)\n    # Discard the first and last lines, these don't contain\n    # disassembled instructions, and are of no interest.\n    disasm = disasm.splitlines()[1:-1]\n    # Extract the address of each instruction, and store these\n    # addresses into the global _unwind_analysis list.\n    disasm = [int(l.lstrip().split()[0], 16) for l in disasm]\n    _unwind_analysis = disasm\n\n\nclass FrameID:\n    def __init__(self, sp, pc):\n        self.sp = sp\n        self.pc = pc\n\n\nclass runto_unwinder(Unwinder):\n    def __init__(self):\n        super().__init__(\"runto_unwinder\")\n\n    def __call__(self, pending_frame):\n\n        # Analyze the function we're going to unwind.\n        global _unwind_analysis\n        if _unwind_analysis is None:\n            analyze()\n\n        # If this is not a frame we handle then return None.\n        pc = pending_frame.read_register(\"pc\")\n        if pc  _unwind_analysis[-1]:\n            return None\n\n        # Create a frame id that will remain consistent throughout the\n        # frame, no matter what $pc we stop at.  We use the $sp value\n        # for the previous frame (this was our $sp on frame entry),\n        # and we use the $pc for the start of the function.\n        #\n        # For the first four and last two instructions, the previous\n        # $sp value can be found in the %rsp register.\n        #\n        # For the fifth and sixth instructions we need to fetch the\n        # previous $sp value from the original stack.\n        rsp = pending_frame.read_register(\"rsp\")\n        if pc  _unwind_analysis[6]:\n            frame_sp = rsp\n        else:\n            frame_sp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" % rsp)\n        func_start = gdb.Value(_unwind_analysis[0])\n        frame_id = FrameID(frame_sp, func_start)\n\n        # Create the unwind_info cache object which holds our unwound\n        # registers.\n        unwind_info = pending_frame.create_unwind_info(frame_id)\n\n        # Calculate the previous register values.  Select the correct\n        # previous value for $rbp based on where we are in the\n        # function.\n        if pc  _unwind_analysis[7]:\n            prev_rbp = pending_frame.read_register(\"rbp\")\n        else:\n            prev_rbp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" % (rsp + 8))\n\n        # We use the previous $sp value in our frame-id, which is handy!\n        prev_rsp = frame_sp\n\n        # The previous $pc is always on the original (incoming) stack.\n        prev_pc = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" % (prev_rsp))\n\n        # And store the previous values into our cache.\n        unwind_info.add_saved_register(\"rsp\", prev_rsp)\n        unwind_info.add_saved_register(\"rbp\", prev_rbp)\n        unwind_info.add_saved_register(\"pc\", prev_pc)\n\n        # Return the cache for GDB to use.\n        return unwind_info\n\n\ngdb.unwinder.register_unwinder(None, runto_unwinder(), replace=True)<\/code><\/pre>\n<p>The most important part of this new version are the three calls to <code>unwind_info.add_saved_register<\/code>; this is how we record the unwound register values. The first argument to these calls is the name of the register we are recording, and the second argument is the value that register had in the previous frame.<\/p>\n<p>The three registers we record are <code>pc<\/code>, <code>rsp<\/code>, and <code>rbp<\/code>. Figuring out the previous value for the first two registers is pretty easy. We already have the previous <code>rsp<\/code> value, remember, this is what we used for our frame-id so that we can reuse that value here.<\/p>\n<p>Recall from our earlier stack diagrams; the return address in <code>main<\/code> was the last thing stored on the original stack, this is what the previous stack-pointer points at, so we can load the return address with this line:<\/p>\n<pre>\n<code class=\"language-python\">        prev_pc = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" \n                                     % (prev_rsp))<\/code><\/pre>\n<p>And this just leaves the previous <code>rbp<\/code> value. Just like we found the previous <code>rsp<\/code> value earlier, the current instruction within <code>run_on_new_stack<\/code> will determine the location of the previous <code>rbp<\/code> value. Initially the previous value is in the <code>rbp<\/code> register, but we store this previous value to the new stack before calling <code>func<\/code>. And so, to find the correct previous value, we need to switch based on the program-counter value, which we do with these lines:<\/p>\n<pre>\n<code class=\"language-python\">        if pc  _unwind_analysis[7]:\n            prev_rbp = pending_frame.read_register(\"rbp\")\n        else:\n            prev_rbp = gdb.parse_and_eval(\"*((unsigned long long *) 0x%x)\" \n                                          % (rsp + 8))<\/code><\/pre>\n<p>The last update is to remove the debug message that we have been printing until now, and instead of returning <code>None<\/code>, return our <code>gdb.UnwindInfo<\/code> object <code>unwind_info<\/code>. This tells GDB that our unwinder has claimed this frame. GDB will use the previous register values stored within <code>unwind_info<\/code> when it needs to unwind through this frame.<\/p>\n<p>So, for the last time, let&#8217;s try our unwinder in GDB:<\/p>\n<pre>\n<code>$ gdb -q demo\nReading symbols from demo...\n(gdb) break func\nBreakpoint 1 at 0x4011b1: file demo.c, line 25.\n(gdb) run\nStarting program: \/tmp\/demo\n\nBreakpoint 1, func () at demo.c:25\n25      printf (\"Hello world\\n\");\n(gdb) source runon-unwind.py\n(gdb) backtrace\n#0  func () at demo.c:25\n#1  0x00000000004011fb in run_on_new_stack () at runon.S:19\n#2  0x00000000004011e0 in main () at demo.c:33\n(gdb)<\/code><\/pre>\n<p>And success! We can now unwind through <code>run_on_new_stack<\/code> back to <code>main<\/code>.<\/p>\n<h3>Summary and conclusions<\/h3>\n<p>Writing custom stack unwinders is not trivial; it requires a good understanding of the function being unwound and the architecture the unwinder is being written for. There is more to GDB&#8217;s unwinder API than has been discussed in this brief introduction. The full details can all be found in the <a href=\"https:\/\/sourceware.org\/gdb\/current\/onlinedocs\/gdb.html\/Unwinding-Frames-in-Python.html\">documentation<\/a>.<\/p>\n<p><span><span lang=\"\" about=\"https:\/\/developers.redhat.com\/user\/746341\" typeof=\"schema:Person\" property=\"schema:name\" datatype=\"\" xml:lang=\"\">aburgess@redhat.com<\/span><\/span><br \/>\n<span>Mon, 06\/19\/2023 &#8211; 07:00<\/span><br \/>\n<a href=\"https:\/\/developers.redhat.com\/author\/andrew-burgess\" hreflang=\"en\">Andrew Burgess<\/a><\/p>\n<\/div>","protected":false},"author":2031,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"slim_seo":{"title":"Debugging in GDB: Create custom stack winders - ITTeacherITFreelance.hk","description":"Debugging in GDB: Create custom stack winders In this article, we will walk through the process of creating a custom stack unwinder for the GNU Project Debugger"},"footnotes":""},"categories":[10700],"tags":[],"_links":{"self":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329306"}],"collection":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/2031"}],"replies":[{"embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=329306"}],"version-history":[{"count":1,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329306\/revisions"}],"predecessor-version":[{"id":329307,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329306\/revisions\/329307"}],"wp:attachment":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=329306"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=329306"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=329306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}