diff --git a/tools/tarantool-gdb.py b/tools/tarantool-gdb.py
index 68152f1a38be46c044ad75f2438f85a59c130164..27b88812e1f7bdabc5472812d995af13088032ae 100644
--- a/tools/tarantool-gdb.py
+++ b/tools/tarantool-gdb.py
@@ -28,6 +28,12 @@ def dump_type(type):
 def equal_types(type1, type2):
     return type1.code == type2.code and type1.tag == type2.tag
 
+def equal_to_any_types(type, types):
+    for t in types:
+        if equal_types(type, t):
+            return True
+    return False
+
 def int_from_address(address):
     return int(address.cast(gdb.lookup_type('uint64_t')))
 
@@ -1747,6 +1753,87 @@ class RlistLut(ListLut):
     )
 
 
+class Stailq(object):
+    gdb_type = gdb.lookup_type('stailq')
+    item_gdb_type = gdb.lookup_type('stailq_entry')
+    entry_ptr_gdb_type = find_type('stailq_entry_ptr')
+
+    def __init__(self, head=None):
+        self.__head = head
+        self.__len = None
+
+    @property
+    def address(self):
+        return self.__head
+
+    def ref(self):
+        return '*({}*){:#x}'.format(
+                self.__head.type.target().tag,
+                int_from_address(self.__head)
+            )
+
+    if entry_ptr_gdb_type is None:
+        @staticmethod
+        def entry(val):
+            return val
+    else:
+        @staticmethod
+        def entry(val):
+            return val['value']
+
+    def __iter__(self):
+        if self.__head is None:
+            return
+        entry = self.entry(self.__head['first'])
+        last_entry = self.entry(self.__head['last'].dereference())
+        while entry != last_entry:
+            yield entry
+            entry = self.entry(entry['next'])
+
+    def __reversed__(self):
+        entries = list(self)
+        for entry in entries[::-1]:
+            yield entry
+
+    def __len__(self):
+        assert self.__head is not None, "__len__ is not applicable to the headless stailq"
+        if self.__len is None:
+            self.__len = sum(1 for _ in self)
+        return self.__len
+
+
+class StailqLut(ListLut):
+    _list_type = Stailq.gdb_type
+    _symbols = (
+        ('swim_task_pool', 'swim_task::in_pool'),
+        ('txn_cache', 'txn::in_txn_cache'),
+    )
+    _containers = (
+        ('applier_data_msg::txs', 'applier_tx::next'),
+        ('applier_tx::rows', 'applier_tx_row::next'),
+        ('cbus_endpoint::output', 'cmsg_poison::msg::fifo'),
+        ('cpipe::input', 'cmsg::fifo'),
+        ('fiber_pool::output', 'cmsg::fifo'),
+        ('iproto_stream::pending_requests', 'iproto_msg::in_stream'),
+        ('MemtxAllocator<Allocator>::gc', 'memtx_tuple::in_gc'),
+        ('memtx_engine::gc_queue', 'memtx_gc_task::link'),
+        ('memtx_tuple_rv_list::tuples', 'memtx_tuple::in_gc'),
+        ('relay::pending_gc', 'relay_gc_msg::in_pending'),
+        ('swim::event_queue', 'swim_member::in_event_queue'),
+        ('txn::stmts', 'txn_stmt::next'),
+        ('Vdbe::autoinc_id_list', 'autoinc_id_entry::link'),
+        ('vy_log_tx::records', 'vy_log_record::in_tx'),
+        ('vy_log::pending_tx', 'vy_log_tx::in_pending'),
+        ('vy_scheduler::processed_tasks', 'vy_task::in_processed'),
+        ('vy_tx::log', 'txv::next_in_log'),
+        ('vy_worker_pool::idle_workers', 'vy_worker::in_idle'),
+        ('wal_msg::commit', 'journal_entry::fifo'),
+        ('wal_msg::rollback', 'journal_entry::fifo'),
+        ('wal_writer::rollback', 'journal_entry::fifo'),
+        ('xrow_update_field::map::items', 'xrow_update_map_item::in_items'),
+    )
+
+
 class TtPrintListEntryParameter(gdb.Parameter):
     name = 'print tt-list-entry'
 
@@ -1867,8 +1954,12 @@ is_item
 
     def __init__(self, val):
         assert self.__class__.__instance_exists, "__instance_exists must be True"
-        assert equal_types(val.type, Rlist.gdb_type), \
-            "expression doesn't refer to list (type: {})".format(dump_type(val.type))
+        assert equal_to_any_types(val.type, (
+                Rlist.gdb_type,
+                Stailq.gdb_type,
+                Stailq.item_gdb_type,
+                Stailq.entry_ptr_gdb_type,
+            )), "expression doesn't refer to list (type: {})".format(dump_type(val.type))
 
         super(TtListPrinter, self).__init__()
 
@@ -1884,12 +1975,14 @@ is_item
         if head is not None:
             head = gdb.parse_and_eval(head)
             if head.type.code == gdb.TYPE_CODE_INT:
-                if equal_types(val.type, Rlist.gdb_type):
+                if equal_to_any_types(val.type, (Rlist.gdb_type, Stailq.gdb_type)):
                     head_type = val.type.pointer()
+                elif equal_to_any_types(val.type, (Stailq.item_gdb_type, Stailq.entry_ptr_gdb_type)):
+                    head_type = Stailq.gdb_type.pointer()
                 else:
                     raise gdb.GdbError("unexpected type: {}".format(dump_type(val.type)))
                 head = head.cast(head_type)
-            elif equal_types(head.type, Rlist.gdb_type):
+            elif equal_to_any_types(head.type, (Rlist.gdb_type, Stailq.gdb_type)):
                 head = head.address
             else:
                 raise gdb.GdbError("unexpected head type {}".format(dump_type(head.type)))
@@ -1910,6 +2003,22 @@ is_item
             else:
                 self.len = Rlist.len(val.address)
 
+        elif equal_types(val.type, Stailq.gdb_type):
+            if head is not None and head != val.address:
+                raise gdb.GdbError("Inconsistent arguments: '-head' is to be used"
+                                   " only when LIST_EXP refers to the single"
+                                   " list item rather than the list itself.")
+            lut = StailqLut
+            self.list = Stailq(val.address)
+
+        elif equal_to_any_types(val.type, (Stailq.item_gdb_type, Stailq.entry_ptr_gdb_type)):
+            if equal_types(val.type, Stailq.entry_ptr_gdb_type):
+                self.val = val['value'].dereference()
+            self.list_type = Stailq.gdb_type
+            lut = StailqLut
+            if head is not None:
+                self.list = Stailq(head)
+
         else:
             raise gdb.GdbError("TtListPrinter.lookup_entry_info: "
                 "unreachable code: unexpected type {}".format(dump_type(val.type)))
@@ -1990,7 +2099,7 @@ is_item
         # If the head of the list is specified the entire list is considered,
         # if the concrete item is specified items before it (after it in case
         # of reverse direction) are not considered
-        if self.val.address != self.list.address:
+        if not equal_types(self.val.type, self.list_type) or self.val.address != self.list.address:
             indexed_items = itertools.dropwhile(
                 lambda indexed_item: indexed_item[1] != self.val.address,
                 indexed_items)
@@ -2023,6 +2132,10 @@ is_item
             yield self.child(item, item_index)
 
 pp.add_printer('rlist', '^rlist$', TtListPrinter)
+pp.add_printer('stailq', '^stailq$', TtListPrinter)
+pp.add_printer('stailq_entry', '^stailq_entry$', TtListPrinter)
+if Stailq.entry_ptr_gdb_type:
+    pp.add_printer('stailq_entry_ptr', '^stailq_entry_ptr$', TtListPrinter)
 
 
 class TtListSelect(gdb.Command):