Alas, I don't think this will be easily doable if at all. gud with gdb works a little differently (and, overall, better) than the other debuggers gud supports because it has a more tighter communication with the underlying debugger, gdb.
For the other debuggers, I think what you'd have to do is first see if there is a gud process running. If so, then try to send a command asking the debugger what state it is in and parse the results of that.
The first part, seeing if there is a gud process and if it is running you could get like this:
(defun gud-process-running-p ()
"Returns true if gud buffer process is running"
(let ((process (get-buffer-process gud-comint-buffer)))
(and gud-comint-buffer process (eq 'run (process-status process)))))
The equivalent for realgud is which allows for multiple debug sessions is:
(defun realgud-process-running-p ()
"Returns true if command buffer process is running"
(let ((cmdbuf (realgud-get-cmdbuf))
(process (get-buffer-process cmdbuf)))
(and cmdbuf process (eq 'run (process-status process)))))
In a gdb-like debugger, you can find out whether the debugger is running using "info program". In jdb, I suppose you could run a command like "where" and look for the error message it reports. For pdb, I'm not sure what the equivalent is for "info program". A "where" command will give a stack trace even after the program terminates.
The lack of features let alone uniformity is one reason why my python debuggers follow the gdb command set. This makes it easier to have a common front end do the same task across different debuggers.
Ok. But now suppose you have figured how the command to run to get status. Next you'd need to send it via gud-call or process-send-string and interpret the results. But see this comment regarding sending information that you don't want echoed.