]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
ast_coredumper: Fix multiple issues
authorGeorge Joseph <gjoseph@sangoma.com>
Fri, 7 Nov 2025 21:39:12 +0000 (14:39 -0700)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Thu, 13 Nov 2025 20:51:08 +0000 (20:51 +0000)
* Fixed an issue with tarball-coredumps when asterisk was invoked without an
absolute path.

* Fixed an issue with gdb itself segfaulting when trying to get symbols from
separate debuginfo files.  The command line arguments needed to be altered
such that the gdbinit files is loaded before anything else but the
`dump-asterisk` command is run after full initialization.

In the embedded gdbinit script:

* The extract_string_symbol function needed a `char *` cast to work properly.

* The s_strip function needed to be updated to continue to work with the
cpp_map_name_id channel storage backend.

* A new function was added to dump the channels when cpp_map_name_id was
used.

* The Channel object was updated to account for the new channel storage
backends

* The show_locks function was refactored to work correctly.

contrib/scripts/ast_coredumper

index d0bad282de23eb2c9b4c84e20bde6540a08d11df..ad752be06883059b9d497bda43915ce0faad20b1 100755 (executable)
@@ -266,6 +266,8 @@ for i in "${!COREDUMPS[@]}" ; do
                libdir=$(dirname "${libfile}")
        }
 
+       [ "$(dirname "${astbin}")" == "." ] && astbin="$(which "${astbin}")" || :
+       astbin=$(realpath -e "${astbin}")
        msg "    ASTBIN: $astbin"
        msg "    MODDIR: $moddir"
        msg "    ETCDIR: $etcdir"
@@ -288,7 +290,7 @@ for i in "${!COREDUMPS[@]}" ; do
        cfname=$(basename "${cf}")
 
        # Produce all the output files
-       ${GDB} -n --batch -q --ex "source $gdbinit" "${astbin}" "$cf" 2>/dev/null | (
+       ${GDB} -n --batch -q --iex "source $gdbinit" -ex "dump-asterisk" "${astbin}" "$cf" 2>/dev/null | (
                of=/dev/null
                while IFS= read -r line ; do
                        if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then
@@ -507,7 +509,7 @@ extract_binary_name() {
 # shellcheck disable=SC2317
 extract_string_symbol() {
        ${GDB} "$1" "$2" -q --batch \
-               -ex "p $3" 2>/dev/null \
+               -ex "p (char *)$3" 2>/dev/null \
                | sed -n -r -e 's/[$]1\s*=\s*[0-9a-fx]+\s+<[^>]+>\s+"([^"]+)"/\1/gp'
        return 0
 }
@@ -771,6 +773,12 @@ def s_strip(value):
     except:
         pass
 
+    try:
+        if value.type.code in [ gdb.TYPE_CODE_ARRAY, gdb.TYPE_CODE_PTR ]:
+            return value.string()
+    except:
+        pass
+
     return str(value).strip('" ') or "<None>"
 
 
@@ -898,6 +906,64 @@ def get_container_rbtree_objects(name, type, on_object=None):
 
     return objs
 
+def get_container_count(name):
+    return int(gdb.parse_and_eval(name).dereference()['elements'])
+
+
+def get_container_map_objects(name, type, on_object=None):
+    """Retrieve a list of objects from a C++ map.
+
+    Expected on_object signature:
+
+        res, stop = on_object(GDB Value)
+
+    The given callback, on_object, is called for each object found in the
+    map. The callback is passed a dereferenced GDB Value object and
+    expects an object to be returned, which is then appended to a list of
+    objects to be returned by this function. Iteration can be stopped by
+    returning "True" for the second return value.
+
+    If on_object is not specified then the dereferenced GDB value is instead
+    added directly to the returned list.
+
+    Args:
+        name: The name of the map
+        type: The type of objects stored in the container
+        on_object: Optional function called on each object found
+
+    Return:
+        A list of map objects
+    """
+    objs = []
+    map = gdb.parse_and_eval(name)
+    node = map['_M_t']['_M_impl']['_M_header']['_M_left']
+    tree_size = map['_M_t']['_M_impl']['_M_node_count']
+    for i in range(0, tree_size):
+        obj_node = (node + 2)
+        obj_p = obj_node.cast(gdb.lookup_type(type).pointer().pointer()).dereference()
+        obj = obj_p.dereference()
+        res, stop = on_object(obj) if on_object else (obj, False)
+        if res:
+            objs.append(res)
+        if stop:
+            return objs
+
+        if node['_M_right'] != 0:
+            node = node['_M_right']
+            while node['_M_left'] != 0:
+                node = node['_M_left']
+        else:
+            tmp_node = node['_M_parent']
+            while node == tmp_node['_M_right']:
+                node = tmp_node
+                tmp_node = tmp_node['_M_parent']
+            if node['_M_right'] != tmp_node:
+                node = tmp_node
+    return objs
+
+def get_map_count(name):
+    map = gdb.parse_and_eval(name)
+    return map['_M_t']['_M_impl']['_M_node_count']
 
 def build_info():
 
@@ -969,7 +1035,7 @@ class TaskProcessor(object):
     def __init__(self, name, processed, in_queue, max_depth,
                  low_water, high_water):
 
-        self.name = s_strip(name)
+        self.name = str(name).strip('"')
         self.processed = int(processed)
         self.in_queue = int(in_queue)
         self.max_depth = int(max_depth)
@@ -979,7 +1045,7 @@ class TaskProcessor(object):
 
 class Channel(object):
 
-    template = ("{name:30} {context:>20} {exten:>20} {priority:>10} {state:>25} "
+    template = ("{name:42} {context:>20} {exten:>20} {priority:>10} {state:>25} "
                 "{app:>20} {data:>30} {caller_id:>15} {created:>30} "
                 "{account_code:>15} {peer_account:>15} {bridge_id:>38}")
 
@@ -989,14 +1055,22 @@ class Channel(object):
               'account_code': 'Accountcode', 'peer_account': 'PeerAccount',
               'bridge_id': 'BridgeID'}
 
+    container = 'current_channel_storage_instance->handle->handle'
+    map = '(((struct mni_channelstorage_driver_pvt *)current_channel_storage_instance->handle)->by_name)'
+
     @staticmethod
     def objects():
 
         try:
-            objs = get_container_hash_objects('channels',
-                'struct ast_channel', Channel.from_value)
-
-            objs.sort(key=lambda x: x.name.lower())
+            driver = gdb.parse_and_eval("current_channel_storage_driver")
+            driver_name = driver['driver_name'].string()
+            if driver_name == "cpp_map_name_id":
+                objs = get_container_map_objects(Channel.map,
+                    'struct ast_channel', Channel.from_value)
+            else:
+                objs = get_container_hash_objects(Channel.container,
+                    'struct ast_channel', Channel.from_value)
+                objs.sort(key=lambda x: x.name.lower())
         except:
             return []
 
@@ -1025,13 +1099,19 @@ class Channel(object):
 
     @staticmethod
     def summary():
+        driver = gdb.parse_and_eval("current_channel_storage_driver")
+        driver_name = driver['driver_name'].string()
+        if driver_name == "cpp_map_name_id":
+            count = get_map_count(Channel.map)
+        else:
+            count = get_container_count(Channel.container)
 
         try:
-            return ("{0} active channels\n"
-                    "{1} active calls\n"
-                    "{2} calls processed".format(
-                        int(gdb.parse_and_eval(
-                            'channels').dereference()['elements']),
+            return ("Channel Driver Name: {0}\n"
+                    "{1} active channels\n"
+                    "{2} active calls\n"
+                    "{3} calls processed".format(driver_name,
+                        count,
                         get("countcalls"),
                         get("totalcalls")))
         except:
@@ -1197,76 +1277,81 @@ DumpAsteriskCommand ()
 end
 
 define show_locks
-   set $n = lock_infos.first
-
-   if $argc == 0
-      printf "                                                                                                                    where_held count-|\n"
-      printf "                                                                                                                         suspended-| |\n"
-      printf "                                                                                                        type- |     times locked-| | |\n"
-      printf "thread         status   file                   line function                             lock name            | lock addr        | | |\n"
-   else
-      printf "thread,status,file,line,function,lock_name,lock_type,lock_addr,times_locked,suspended,where_held_count,where_held_file,where_held_line,where_held_function,there_held_thread\n"
-   end
-
-   while $n
-      if $n->num_locks > 0
+  set $n = lock_infos.first
+
+  if $argc == 0
+    printf "%s\n", "                                                                                                                                                                where_held count-|"
+    printf "%s\n", "                                                                                                                                                                   suspended-|   |"
+    printf "%s\n", "                                                                                                                                                 type-|     times locked-|   |   |"
+    printf "%-14s %-36s %6s %-42s %-8s %-36s %3s %-14s %3s %3s %3s\n",\
+      "thread","file","line","function","status","lock name","|","lock addr","|","|","|"
+    printf "%s\n", "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
+
+  else
+    printf "thread,status,file,line,function,lock_name,lock_type,lock_addr,times_locked,suspended,where_held_count,where_held_file,where_held_line,where_held_function,there_held_thread\n"
+  end
+
+  while $n
+    if $n->num_locks > 0
       set $i = 0
       while $i < $n->num_locks
-         if $n->locks[$i]->suspended == 0
-            if ((ast_mutex_t *)$n->locks[$i]->lock_addr)->tracking
-               if $n->locks[$i]->type > 0
-                  set $track = ((ast_rwlock_t *)$n->locks[$i]->lock_addr)->track
-               else
-                  set $track = ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
-               end
+        if $n->locks[$i]->suspended != 47
+          if $n->locks[$i]->pending > 0
+            set $status = "waiting"
+          end
+          if $n->locks[$i]->pending < 0
+            set $status = "failed"
+          end
+          if $n->locks[$i]->pending == 0
+            set $status = "holding"
+          end
+
+          if $n->locks[$i]->type == 0
+            set $ltype = "M"
+          end
+          if $n->locks[$i]->type == 1
+            set $ltype = "RD"
+          end
+          if $n->locks[$i]->type == 2
+            set $ltype = "WR"
+          end
+
+          if ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
+            if $n->locks[$i]->type > 0
+              set $track = ((ast_rwlock_t *)$n->locks[$i]->lock_addr)->track
+            else
+              set $track = ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
             end
+          end
+          if $track
             set $reentrancy = $track->reentrancy
-            set $pending = $n->locks[$i]->pending
-            if $argc > 0
-               printf "%p,%d,%s,%d,%s,%s,%d,%p,%d,%d,%d",\
-                  $n->thread_id, $n->locks[$i]->pending, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
-                  $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
-                  $n->locks[$i]->suspended, $track->reentrancy
-               if $reentrancy
-                  if $pending
-                     printf ",%s,%d,%s,%p", $track->file[0], $track->lineno[0], $track->func[0], $track->thread[0]
-                  end
-               end
-            else
-               if $n->locks[$i]->pending < 0
-                  printf "%p failed   %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
-                     $n->thread_id,\
-                     $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
-                     $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
-                     $n->locks[$i]->suspended, $track->reentrancy
-               end
-               if $n->locks[$i]->pending == 0
-                  printf "%p holding  %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
-                     $n->thread_id,\
-                     $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
-                     $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
-                     $n->locks[$i]->suspended, $track->reentrancy
-               end
-               if $n->locks[$i]->pending > 0
-                  printf "%p waiting  %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
-                     $n->thread_id,\
-                     $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
-                     $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
-                     $n->locks[$i]->suspended, $track->reentrancy
-               end
-               if $reentrancy
-                  if $pending
-                     printf "\n               held at: %-20s %6d %-36s by 0x%08lx", $track->file[0], $track->lineno[0], $track->func[0], $track->thread_id[0]
-                  end
-               end
+          else
+            set $reentrancy = 0
+          end
+          set $pending = $n->locks[$i]->pending
+          if $argc > 0
+            printf "%p,%d,%s,%d,%s,%s,%d,%p,%d,%d,%d",\
+              $n->thread_id, $n->locks[$i]->pending, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
+              $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
+              $n->locks[$i]->suspended, $reentrancy
+            if $reentrancy && $pending
+              printf ",%s,%d,%s,%p", $track->file[0], $track->lineno[0], $track->func[0], $track->thread[0]
             end
-            printf "\n"
-         end
-         set $i = $i + 1
+          else
+            printf "%14p %-36s %6d %-42s %-8s %-36s %3s %-14p %3d %3d %3d", \
+              $n->thread_id, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func, $status, \
+              $n->locks[$i]->lock_name, $ltype, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
+              $n->locks[$i]->suspended, $reentrancy
+            if $reentrancy && $pending
+              printf "\n               held at: %s:%d %s() by 0x%08lx", \
+                $track->file[0], $track->lineno[0], $track->func[0], $track->thread_id[0]
+            end
+          end
+          printf "\n"
+        end
+        set $i = $i + 1
       end
     end
     set $n = $n->entry->next
   end
 end
-
-dump-asterisk