Rem Rem Copyright (c) Oracle Corporation 1995, 1996. All Rights Reserved. Rem Rem NAME Rem dbmspb.sql - ProBe (PL/SQL debugger) server-side packages. Rem Rem DESCRIPTION Rem Server-side packages that implement server-side Probe support. Rem Rem NOTES Rem * Must be installed as SYS. Rem Rem * This package is not intended to be used directly by the ordinary Rem user: it is a low-level interface to Probe services. Rem REM **************************************************************** REM * THIS PACKAGE MUST NOT BE ALTERED BY THE CUSTOMER. DOING SO * REM * COULD CAUSE INTERNAL ERRORS AND SECURITY VIOLATIONS IN THE * REM * RDBMS. * REM **************************************************************** -- TODO -- * For each function we have to document what "reasons" can be returned -- * for functions that take records, we have to document which fields -- get set, or read -- * Need to figure out how subsequent programs should be debugged -- * Add a 'set_timeout' call (that takes a timeout)? -- * Make sure all "????" are resolved. -- OVERVIEW -- In order to debug server-side stored procedures, triggers that are executed -- from SQL statements, two connections are required. One connection is the -- "target connection" which is running the target code that needs to be -- debugged; this connection is first initialized in "debug-mode" and -- then the target code can be executed. -- The other connection is the "debug connection" which is used to debug ehe -- target code, that is, set breakpoints, examine values, set values etc. -- The 'target connection' needs to do the following: -- -- Target Connection -- ***************** -- +------------+ -- | Initialize | -- | connection |--> return unique session_id -- | for | -- | debugging | -- +------------+ -- | -- +------------------------->| -- | | -- | +---------------+-------------+ -- | V | V -- | +------------+ | +------------+ -- | | start | | | stop | -- | | debugging | | | debugging | -- | | "debug_on" | | | "debug_off"| -- | +------------+ | +------------+ -- | V V V -- | +---------------+-------------+ -- | V -- | +------------+ ** when executing SQL, triggers can -- | | Execute | be debugged -- | | PLSSQL | -- | | progams | -- | | or SQL** | -- | +------------+ -- +--------------------------| -- V -- -- Note 1: For get/set value you have to compile triggers, procedure, functions, -- and package with DEBUG information. You can do this by executing: -- -- ALTER [PROCEDURE|FUNCTION|PACKAGE|TRIGGER] COMPILE DEBUG; -- -- You can also make sure "future" compilations within a session -- (including compilations of anynoymous blocks) are compiled with -- debug information, by executing: -- -- ALTER SESSION SET PLSQL_DEBUG=TRUE; -- -- Note 2: When the target connection and debug connection are executed from -- the same client application, the target connection has to be in -- "non-blocking" mode, since the target connection is executing -- when you execute statements in the debug connection to debug the -- target connection. -- -- Now to debug the PL/SQL and SQL programs, the 'debug connection' needs to -- attach to the right session. To do so, you need to pass the -- 'debug_session_id' returned from the initialize call in the target -- connection to the attach_session() call. After that you can attach the -- debugger to the program being executed, by calling the attach_program() -- procedure. Now the program being executed can be debugged, i.e. get_value, -- set_value, set break points etc. -- So the debugger session would look like: -- -- Debug Connection -- **************** -- +------------+ -- | attach | -- unique debug --> | session | -- session id | | -- +------------+ -- +-------------------------->| -- | +-----------+<-----------+ -- | | | | -- | | +----------------+ | -- | | | set/delete | | -- | | | disable/enable | | -- | | | breakpoints | | -- | | +----------------+ | -- | | | | -- | |<---------+-------------+ -- | | -- | V -- | +-------------+ -- | | | -- | | synchronize | -- | | | -- | +-------------+ -- | | -- | +------------------------>| -- | | +---------------------->| -- | | | V -- | | | +--------+---------+ -- | | | | | | -- | | | V V V -- | | | +--------+ +--------+ +---------------+ -- | | | | get | | get/set| |set/delete | -- | | | | source | | value | |disable/enable | -- | | | | | | | |breakpoints | -- | | | +--------+ +--------+ +---------------+ -- | | | | | | -- | | | V V V -- | | | +--------+---------+ -- | | | | -- | | +-----------------------| -- | | V -- | | +--------+ -- | | |continue| <-- debugflags * -- | +--------------------| | -- | +--------+ -- | | -- +---------------------------+ -- next program to debug V -- +------------+ -- | detach | -- | session | -- +------------+ -- -- Note * : Debugflags are flags like "break next line", "break on exception" -- etc. The flags can be combined into a bitmask allowing you to -- define Breaks on multiple "events". -- ---------------------------- NOTES/QUESTIONS ---------------------------- -- 1. Would be nice to implement an indexed-table interface for several -- of the routines. (show_source, print_backtrace, print_breakpoints). -- 2. What about deferred operations? Especially authentication of -- deferred breakpoints. -- 3. How are diagnostics done? -- 4. Instead of having two separate diagnostics calls, debug session should -- tell target session to switch to/from diagnostic mode. That way the -- 'session' can be taken in and out of diagnostic mode. -- -- CREATE OR REPLACE PACKAGE DBMS_DEBUG IS ------------------------------ -- PUBLIC CONSTANTS and TYPES ----------------------------- PROGRAM_INFO --------------------- -- The type Program_info is used to specify breakpoints in a particular -- package, procedure, function, trigger etc. Values for namespaces -- are defined in this package. TYPE program_info IS RECORD ( Namespace BINARY_INTEGER, Name VARCHAR2(30), Owner VARCHAR2(30), Dblink VARCHAR2(30) ); ------------------------------- RUNTIME_INFO ----------------------- -- The type run_time info is used primarily to give "context" information -- about the running program. TYPE runtime_info IS RECORD ( Line# BINARY_INTEGER, Terminated BINARY_INTEGER, Breakpoint BINARY_INTEGER, StackDepth BINARY_INTEGER, InterpreterDepth BINARY_INTEGER, Reason BINARY_INTEGER, -- reason for suspension Program program_info ); ------------------------------- NAMESPACES ----------------------------- -- Program units on the server reside in different namespaces. When -- setting a breakpoint it is necessary to specify the desired namespace -- (to distinguish between a package spec and a package body, for example). -- -- namespace_pkgspec_or_toplevel includes the following: -- package specs -- top-level procedures and functions -- anonymous blocks namespace_pkgspec_or_toplevel CONSTANT BINARY_INTEGER := 1; namespace_pkg_body CONSTANT BINARY_INTEGER := 2; namespace_trigger CONSTANT BINARY_INTEGER := 3; --------------------------- BREAK FLAGS -------------------------------- -- The "continue" procedure takes a bitmask of the events which are of -- interest. The possible values -- break_exception CONSTANT BINARY_INTEGER := 2; break_any_call CONSTANT BINARY_INTEGER := 12; -- 4 | 8 break_return CONSTANT BINARY_INTEGER := 16; break_next_line CONSTANT BINARY_INTEGER := 32; break_any_return CONSTANT BINARY_INTEGER := 512; break_handler CONSTANT BINARY_INTEGER := 2048; abort_execution CONSTANT BINARY_INTEGER := 8192; -- Not supported yet: break_RPC CONSTANT BINARY_INTEGER := 4096; -- Reserved internal values: -- 4 and 8 for CALL/XCAL -- 64 and 128 for ICDs ------------------------- INFORMATION FLAGS --------------------------- -- These are flags that can be passed as the 'info_requested' parameter -- to synchronize, continue, and get_runtime_info. -- info_getStackDepth CONSTANT binary_integer := 2; info_getLineinfo CONSTANT binary_integer := 8; -- info_getBreakpoint - more information about the current breakpoint, -- if execution is paused at a breakpoint. info_getBreakpoint CONSTANT binary_integer := 4; ------------------------- REASONS ------------------------------------- -- Reasons for suspension. After continue is executed, the program will -- either run to completion or break on some line. The reason for this -- suspension might be: reason_none CONSTANT BINARY_INTEGER := 0; reason_interpreter_starting CONSTANT BINARY_INTEGER := 2; reason_breakpoint CONSTANT BINARY_INTEGER := 3; reason_enter CONSTANT BINARY_INTEGER := 6; -- procedure entry reason_return CONSTANT BINARY_INTEGER := 7; -- procedure return reason_finish CONSTANT BINARY_INTEGER := 8; -- procedure is finished reason_line CONSTANT BINARY_INTEGER := 9; -- reached a new line reason_interrupt CONSTANT BINARY_INTEGER := 10; -- an interrupt occurred reason_exception CONSTANT BINARY_INTEGER := 11; -- an exception was raised reason_exit CONSTANT BINARY_INTEGER := 15; -- interpreter is exiting reason_handler CONSTANT BINARY_INTEGER := 16; -- start of exception-handler reason_timeout CONSTANT BINARY_INTEGER := 17; -- a timeout occurred reason_instantiate CONSTANT BINARY_INTEGER := 20; -- instantiation block reason_abort CONSTANT BINARY_INTEGER := 21; -- interpeter is aborting -- Not yet supported: reason_watch CONSTANT BINARY_INTEGER := 14; -- watched value changed reason_rpc CONSTANT BINARY_INTEGER := 18; -- an RPC started reason_sql CONSTANT BINARY_INTEGER := 4; -- executing SQL -- reason_unhandled - execution terminated due to an unhandled exception reason_unhandled CONSTANT BINARY_INTEGER := 19; -- Reserved internal values: -- 1 for internal init -- 5 unused -- 12 for ICD call -- 13 for ICD return ------------------------------ ERROR CODES ------------------------------ -- These values are returned by the various functions that are called in -- the debug connection (synchronize, continue, set_breakpoint, etc). -- success CONSTANT binary_integer := 0; -- Statuses returned by get_value and set_value: error_bogus_frame CONSTANT binary_integer := 1; error_no_debug_info CONSTANT binary_integer := 2; error_no_such_object CONSTANT binary_integer := 3; error_unknown_type CONSTANT binary_integer := 4; -- Statuses returned by set_value: error_illegal_value CONSTANT binary_integer := 5; error_illegal_null CONSTANT binary_integer := 6; error_value_malformed CONSTANT binary_integer := 7; error_other CONSTANT binary_integer := 8; error_name_incomplete CONSTANT binary_integer := 11; -- Statuses returned by the breakpoint functions: error_illegal_line CONSTANT binary_integer := 12; error_no_such_breakpt CONSTANT binary_integer := 13; error_idle_breakpt CONSTANT binary_integer := 14; error_stale_breakpt CONSTANT binary_integer := 15; error_bad_handle CONSTANT binary_integer := 16; -- General error codes (returned by many of the dbms_debug routines) error_unimplemented CONSTANT binary_integer := 17; -- NYI functionality -- error_deferred: just a warning that the request was deferred for later -- execution. Currently never signalled. error_deferred CONSTANT binary_integer := 27; -- error_exception: an exception was raised in the DBMS_DEBUG or Probe -- packages on the server. error_exception CONSTANT binary_integer := 28; -- error_communication indicates that some error (other than a timeout) -- occurred. error_communication CONSTANT binary_integer := 29; error_timeout CONSTANT binary_integer := 31; -- Error codes that only apply to client-side PL/SQL error_pbrun_mismatch CONSTANT binary_integer := 9; error_no_rph CONSTANT binary_integer := 10; error_probe_invalid CONSTANT binary_integer := 20; error_upierr CONSTANT binary_integer := 21; error_noasync CONSTANT binary_integer := 22; error_nologon CONSTANT binary_integer := 23; error_reinit CONSTANT binary_integer := 24; error_unrecognized CONSTANT binary_integer := 25; error_synch CONSTANT binary_integer := 26; error_incompatible CONSTANT binary_integer := 30; ------------------------------ -- PUBLIC VARIABLES -- The timeout value (used by all the functions and procedures that are -- called in the debug connection.) -- default_timeout BINARY_INTEGER := 3600; -- 60 minutes ------------------------ TARGET CONNECTION Section ------------------------ -- -- These functions and procedures are to be executed in the target connection -- (the session that is to be debugged). -- ----------------------- INITIALIZE --------------------------- -- Set up the plumbing for the debugger. Register the given session_id -- or ask DBMS_DEBUG to generate a unique one for you. -- -- PARAMETERS -- debug_session_id - a session-id name. Since DBMS_DEBUG will generate -- a unique name for you, it is recommended that you -- take the default value. -- diagnostics - whether to dump diagnostic output to the tracefile -- -- RETURNS -- the newly-registered debug-session-id. -- FUNCTION initialize (debug_session_id IN VARCHAR2 := NULL, diagnostics in BINARY_INTEGER := 0) RETURN VARCHAR2; ----------------------- DEBUG_ON ----------------------------- -- Notify the target connection that debugging is to take place -- whenever PL/SQL is executed on the server in that session. -- This must be done before any debugging can take place. -- -- no_client_side_plsql_engine should be left to its default value -- unless the debugging session is taking place from a client-side -- plsql engine. -- PROCEDURE debug_on (no_client_side_plsql_engine BOOLEAN := TRUE); ----------------------- DEBUG_OFF ---------------------------- -- Notify the target connection that debugging is no longer to take -- place in that session. -- It is not necessary to call this function before logging the -- session off. -- -- NOTES -- The server does not handle this entrypoint specially. Therefore -- it will attempt to debug this entrypoint. This will be fixed -- in the next release. -- PROCEDURE debug_off; ------------------------- DEBUG CONNECTION Section ------------------------- -- -- These functions and procedures are to be executed in the debug connection -- only. -- ----------------------- ATTACH_SESSION ----------------------- -- Notify the debug connection about the target program. -- -- PARAMETERS -- debug_session_id - -- diagnostics - -- -- NOTES: -- The 'diagnostics' variable will probably go away in the next -- version. -- PROCEDURE attach_session (debug_session_id IN VARCHAR2, diagnostics IN BINARY_INTEGER := 0); ------------------------------ SYNCHRONIZE ------------------------------ -- This is the first function to be executed by the 'debug connection'. -- It waits until the target program has started execution. -- -- PARAMETERS -- run_info - structure in which to write information about the program -- By default this will include information about what program -- is executing and at which line execution has paused. -- info_requested - optional bit-field in which to request information -- other than the default (which is info_getStackDepth + -- info_getLineInfo). Passing a value of 0 means that no -- information is requested at all. -- -- RETURNS -- success -- error_timeout - timed out before the program started execution -- error_communication - other communication error -- FUNCTION synchronize (run_info OUT runtime_info, info_requested IN BINARY_INTEGER := NULL) RETURN BINARY_INTEGER; ----------------------- SHOW_SOURCE ----------------------- -- To be executed by the 'debug connection' only. -- shows the source of the code that is being debugged. -- the low and high arguments give the first line and the -- last to be returned. You can also provide a window -- argument that represents the number of lines before and -- the number of lines after the current line that need to -- be returned. -- The source will be returned in the buflen varaible, and can -- contain newlines. If source doesn't fit in bufferlength (buflen) -- then additional pieces can be retrieved using the 'get_more_source' -- procedure. Note that pieces will return the additional number -- of pieces that need to be retrieved. -- -- PARAMETERS -- first_line - smallest line-number to print -- last_line - largest line-number to print -- window - 'window' of lines - the number of lines around the -- current source line. -- print_arrow - non-zero means to print an arrow before the current line -- buffer - buffer in which to place the source listing -- buflen - length of buffer $$$ Why do we have this? -- pieces - set to non-zero if not all the source could be placed -- into the given buffer -- -- NOTES: -- We will be providing an overloaded version that returns an indexed -- table instead of one long string. -- PROCEDURE show_source (first_line IN BINARY_INTEGER, last_line IN BINARY_INTEGER, window IN BINARY_INTEGER, print_arrow IN BINARY_INTEGER, buffer IN OUT VARCHAR2, buflen IN BINARY_INTEGER, pieces OUT BINARY_INTEGER); ----------------------- GET_MORE_SOURCE ------------------- -- To be executed by the 'debug connection' only. -- When source doesn't fit in buffer provided in the "show_source" -- procedure, this procedure provides additional source. PROCEDURE get_more_source (buffer IN OUT VARCHAR2, buflen IN BINARY_INTEGER, piece# IN BINARY_INTEGER); ---------------------- PRINT_BACKTRACE ------------------- -- Print a backtrace listing of the current execution stack. -- Should only be called if a program is currently executing. -- -- NOTES -- We will be providing an overloaded version that returns the -- output in an indexed table. -- PROCEDURE print_backtrace (listing in out VARCHAR2); ----------------------- CONTINUE -------------------------- -- Continue execution, using the given breakflags. -- The target program will run to completion or pause at the next event -- or breakpoint. run_info.reason will contain the "reason" for -- stopping. -- See 'synchronize' for details about return-values. -- FUNCTION continue (run_info IN OUT runtime_info, breakflags IN BINARY_INTEGER, info_requested IN BINARY_INTEGER := null) RETURN BINARY_INTEGER; -------------------------- SET_BREAKPOINT ---------------------- -- Set a breakpoint in a program unit, which persists for the current -- session. Execution will pause if the target program reaches the -- breakpoint. -- -- PARAMETERS -- program information about the program unit in which the breakpoint -- is to bet set -- line# the line at which the breakpoint is to be set -- breakpoint# on successful completion, will contain the unique -- breakpoint number by which to refer to the breakpoint. -- -- RETURNS -- success -- error_illegal_line - can't set a breakpoint at that line -- error_bad_handle - no such program unit exists -- FUNCTION set_breakpoint (program IN program_info, line# IN BINARY_INTEGER, breakpoint# OUT BINARY_INTEGER) RETURN BINARY_INTEGER; -------------------------- DELETE_BREAKPOINT ---------------------- -- To be executed by the 'debug connection' only. -- Deletes a breakpoint. -- -- RETURNS -- success -- error_no_such_breakpt - no such breakpoint exists -- error_idle_breakpt - breakpoint exists but is inactive (ie. the -- breakpoint was already deleted) -- error_stale_breakpt - the program unit was redefined since the -- breakpoint was set -- FUNCTION delete_breakpoint (breakpoint IN BINARY_INTEGER) RETURN BINARY_INTEGER; -------------------------- DISABLE_BREAKPOINT ---------------------- -- To be executed by the 'debug connection' only. -- With this procedure the breakpoint will still be there, but not be -- active. After disabling the breakpoint needs to be enabled to make it -- active -- -- RETURNS -- success -- error_no_such_breakpt - no such breakpoint exists -- error_idle_breakpt - breakpoint exists but is inactive (ie. the -- breakpoint was already deleted) -- FUNCTION disable_breakpoint (breakpoint IN BINARY_INTEGER) RETURN BINARY_INTEGER; -------------------------- ENABLE_BREAKPOINT ---------------------- -- To be executed by the 'debug connection' only. -- Reverse of disabling. This procedure "activates" an exsiting breakpoint -- -- RETURNS -- success -- error_no_such_breakpt - no such breakpoint exists -- error_idle_breakpt - breakpoint exists but is inactive (ie. the -- breakpoint was already deleted) FUNCTION enable_breakpoint (breakpoint IN BINARY_INTEGER) RETURN BINARY_INTEGER; -------------------------- SHOW_BREAKPOINTS ---------------------- -- To be executed by the 'debug connection' only. -- This procedures prints all breakpoints in the "listing" buffer. -- -- NOTES: -- Next release will contain an overloading that uses indexed tables. -- PROCEDURE show_breakpoints (listing IN OUT VARCHAR2); ------------------------------- GET_VALUE ------------------------------- -- Get a value from the currently-executing program. -- -- RESTRICTIONS/BUGS -- Doesn't yet work for package variables. -- -- PARAMETERS -- variable_name the name of the variable or parameter -- frame# the frame in which it lives (0 means the current -- procedure) -- scalar_value its value -- format an optional dat format to use, if meaningful. -- -- RETURNS -- success -- error_bogus_frame - frame# number does not exist -- error_no_debug_info - entrypoint has no debug information -- error_no_such_object - variable_name does not exist in frame# -- error_unknown_type - the type information in the debug information -- is illegible -- FUNCTION get_value (variable_name IN VARCHAR2, frame# IN BINARY_INTEGER, scalar_value OUT VARCHAR2, format IN VARCHAR2 := NULL) RETURN BINARY_INTEGER; -------------------------- SET_VALUE ---------------------------- -- Set a value in the currently-executing program. -- -- RESTRICTIONS/BUGS -- Doesn't yet work for package variables. -- -- PARAMETERS -- frame# - the frame in which the value is to be set (0 means the -- currently executing frame. -- assignment_statement - an assignment statement (which must be legal -- PL/SQL) to execute in order to set the value. -- For example, 'x := 3;' -- Note that only scalar values are supported in -- this release - the right hand side of the -- assignment statement must be a scalar. -- -- RETURNS -- success -- error_illegal_value - not possible to set it to that value -- error_illegal_null - cant set it to NULL because object type -- specifies it as 'not null' -- error_value_malformed - value is not a scalar -- error_name_incomplete - the assignment statement does not resolve to -- a scalar. For example 'x := 3;', if x is -- a record. -- error_other -- FUNCTION set_value(frame# IN binary_integer, assignment_statement IN varchar2) RETURN BINARY_INTEGER; -------------------------- PROBE_VERSION ------------------------- -- Return the version number of the Probe package on the server. -- This is used mainly by client-side. PROCEDURE probe_version (major out BINARY_INTEGER, minor out BINARY_INTEGER); -------------------------------- ABORT -------------------------------- -- Abort the currently-executing program. -- -- NOT YET SUPPORTED. To abort a program call 'continue' with -- execution flags 'abort_execution'. -- FUNCTION ABORT return BINARY_INTEGER; -------------------------- DETACH_SESSION ---------------------- -- Detach from the currently attached session - ie. stop debugging -- the target program. This procedure may be executed at any time, -- but it does not do any communication with the target session, -- so doing this may cause the target session to hang if it is in -- the middle of executing PL/SQL, or if it starts executing PL/SQL -- subsequently. -- PROCEDURE detach_session; --------------------------- get_runtime_info --------------------------- -- This function returns information about the current program. It is -- only needed if the 'info_requested' parameter to synchronize or -- continue was set to 0. -- -- Currently only used by client-side PL/SQL. -- FUNCTION get_runtime_info (info_requested IN BINARY_INTEGER, run_info OUT runtime_info) return BINARY_INTEGER; --------------------- GET_ENCODED_STACK_FOR_CLIENT --------------------- -- Return an encoded form of one or more stack frames. Only useful if -- the caller is client-side PL/SQL, since the decoder is built into the -- PL/SQL engine. -- -- PARAMETERS -- start_frame -- frame_count - number of frames to fetch -- flags - currently unused -- max_string_length - truncate strings at this value (NYI) -- max_index_values - only fetch this many index table elements (NYI) -- pbrun_version - client version -- tidl_buf - buffer in which to place encoded TIDL -- tidl_version - version-number of the generated TIDL -- PROCEDURE get_encoded_stack_for_client( start_frame IN BINARY_INTEGER, frame_count IN BINARY_INTEGER, flags IN BINARY_INTEGER, max_string_length IN BINARY_INTEGER, max_index_values IN BINARY_INTEGER, pbrun_version IN BINARY_INTEGER, tidl_buf IN OUT VARCHAR2, tidl_version OUT BINARY_INTEGER ); END DBMS_DEBUG; / -- show errors grant execute on DBMS_DEBUG to public; drop public synonym DBMS_DEBUG; create public synonym DBMS_DEBUG for sys.DBMS_DEBUG;