Subject: bug#3794: Error in json from gdb-ui

From: Dmitry Dzhus <[email-masked]>
Date: Fri, 10 Jul 2009 17:26:37 +0400

> I tried M-x gdb to run emacs under gdb.  The command line was
>
>   gdb -i=mi ~/src/emacs/src/emacs
>
> and I got the error '(json-object-format ":" 44).  Here is the backtrace:

Thank you for reporting this bug.

I could reproduce your problem and I wrote a workaround which fixes the
bug for me. Could you please try the attached patch for gdb-mi.el?
diff -r 36335b2a0438 -r 392a117f6afc gdb-mi.el
--- a/gdb-mi.el	Fri Jul 10 14:57:26 2009 +0400
+++ b/gdb-mi.el	Fri Jul 10 16:52:55 2009 +0400
@@ -1570,7 +1570,7 @@
   (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
     (erase-buffer)))
 
-(defun json-partial-output (&optional fix-key)
+(defun json-partial-output (&optional fix-key fix-list)
   "Parse gdb-partial-output-buffer with `json-read'.
 
 If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurences from
@@ -1579,15 +1579,37 @@
 -break-info are examples of MI commands which issue such
 responses.
 
+If FIX-LIST is non-nil, \"FIX-LIST={..}\" is replaced with
+\"FIX-LIST=[..]\" prior to parsing. This is used to fix broken
+-break-info output when it contains breakpoint script field
+incompatible with GDB/MI output syntax.
+
 Note that GDB/MI output syntax is different from JSON both
 cosmetically and (in some cases) structurally, so correct results
 are not guaranteed."
   (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
     (goto-char (point-min))
-    (while (re-search-forward (concat "[\\[,]\\(" fix-key "=\\)") nil t)
-      (replace-match "" nil nil nil 1))
-     (goto-char (point-min))
-     (insert "{")
+    (when fix-key
+      (save-excursion
+        (while (re-search-forward (concat "[\\[,]\\(" fix-key "=\\)") nil t)
+          (replace-match "" nil nil nil 1))))
+    (when fix-list
+      (save-excursion
+        ;; Find positions of brackets which enclose broken list
+        (while (re-search-forward (concat fix-list "={\"") nil t)
+          (let ((p1 (goto-char (- (point) 2)))
+                (p2 (progn (forward-sexp)
+                           (1- (point)))))
+            ;; Replace braces with brackets
+            (save-excursion
+              (goto-char p1)
+              (delete-char 1)
+              (insert "[")
+              (goto-char p2)
+              (delete-char 1)
+              (insert "]"))))))
+    (goto-char (point-min))
+    (insert "{")
     ;; Wrap field names in double quotes and replace equal sign with
     ;; semicolon.
     ;; TODO: This breaks badly with foo= inside constants
@@ -1691,7 +1713,7 @@
 
 (defun gdb-breakpoints-list-handler-custom ()
   (let ((breakpoints-list (gdb-get-field 
-                           (json-partial-output "bkpt")
+                           (json-partial-output "bkpt" "script")
                            'BreakpointTable 'body)))
     (setq gdb-breakpoints-list nil)
     (insert "Num\tType\t\tDisp\tEnb\tHits\tAddr       What\n")

Background information:

That's one of the GDB/MI syntax inconsistencies coming up in this case.
The problem is caused by a script being attached to `init_sys_modes`
breakpoint in `.gdbinit`. When GDB/MI includes script information in
`-break-info`, it violates its own syntax by wrapping script field value
in curly braces (like for tuples) instead of brackets (like for lists,
which should be the case for script listing), for example:

script={"silent","xgetptr Vinitial_window_system","set $tem = ( struct
Lisp_Symbol *) $ptr","xgetptr $tem->xname","set $tem = (struct
Lisp_String *) $ptr","set $tem = (char *) $tem->data","if $tem[0] == 'x'
&& $tem[1] == '\0'","break x_error_quitter","end","continue"}

Whereas according to GDB/MI Output Syntax tuples (enclosed in {}) may
contain only variable=value pairs.

As the result, the JSON parser used in gdb-mi.el chokes. We handle this
nasty case by turning `script` value into what it's meant to be, which
is a list, by replacing { -> [ and ] -> }.
-- 
Happy Hacking.

http://sphinx.net.ru
む