/* PL/I symbolic debugger module handling breakpoint-related commands */ breakcmd: procedure; %include 'knldef.pli'; %include 'scandef.pli'; %include 'workdef.pli'; %include 'initdef.pli'; %include 'putdef.pli'; %include 'segdef.pli'; %include 'moddef.pli'; %include 'brksymdef.pli'; %include 'breakdef.pli'; %include 'statement.inc'; %include 'overlaym.inc'; %include 'tiqio.inc'; %include 'plioctal.inc'; %include 'findbpt.inc'; /* subroutines from PLIUTL & PLIMMR: */ dcl trim entry(char(*)) returns(char(10) varying); dcl cancel_all_mode fixed bin(1), ibpt fixed bin(15), /* variables are made static only because static references often take less code */ (i, j, x) fixed bin(15) static, ttype fixed bin(7), /*scratch variables*/ tname char(31) varying static; /*scratch*/ /**************************************************************************************************************/ i = nxtokenis(' SET SE '); /*SET keyword is always optional*/ startp = nextp; /*(this affects all subsequent commands)*/ /*********************** * Cancel Breakpoint * ***********************/ /*note: cancel_a_break procedure has been temporarily moved from here to the end of this source file, split as separate procedure so it can be called from gocmd*/ if nxtokenis(' CANCEL CAN NO N ') then if nxtokenis(break) then do; cancelbreak: cancel_all_mode = false; if nxtokenis('/') then do; if ^nxtokenis('ALL') then call error('The only current cancel break qualifier is /ALL'); call endscan; cancel_all_mode = true; ibpt = lbound(breakpoint,1); j = hbound(breakpoint,1); end; else do; cancel_next: ttype = nxtokenis(',') /*comma is optional*/; call statement; if debprocedure_define_level ^= 0 then goto cancel_done; /*execute only if not defining a do group*/ ibpt = find_breakpoint(statement_address, statement_overlay); if ibpt = bpt_not_found then do; call warning('there''s no breakpoint set at that location'); goto cancel_done; end; j = ibpt; /* cancel only location ibpt */ end; do while (ibpt<=j); if overlay_mapped(breakpoint(ibpt).overlay) then call cancel_a_break(ibpt); /*if accessable, cancel it now*/ else breakpoint(ibpt).to_be_cancelled = true; /*else flag for deferred cancel when becomes accessable*/ /*(in case it's memory-resident overlay)*/ ibpt = ibpt+1; end; cancel_done: if nxtokenis(';') ! cancel_all_mode then goto command_done; goto cancel_next; end; nextp = startp; if nxtokenis(' NOBREAK NOBR NOB NB ') then goto cancelbreak; /******************** * Set Breakpoint * ********************/ /*note: set_a_break procedure has been temporarily moved from here to the end of this source file, split as separate procedure so it can be called from gocmd*/ if nxtokenis(break) /*SET keyword has been factored out*/ then do; in_set_break = true; /*for error-handling*/ setbreaknext: tname = '1'; if nxtokenis('/') then do; if ^nxtokenis(' AFTER AFT AF ') then goto bad_input; ttype = nxtokenis(':'); /*colon is optional*/ on size goto bad_input; (size): if nexttoken(tname) ^= decimal_constant_type then goto bad_input; (size): j = tname; if j <= 1 then bad_input:call error('The only current break qualifier is /AFTER:n where 2<=n<=32767'); end; call statement; if debprocedure_define_level = 0 then do; /*execute only if not defining a do group*/ ibpt = find_breakpoint(statement_address, statement_overlay); if ibpt ^= bpt_not_found & statement_address ^= to_be_determined /***temp**/ then do; if statement_address ^= breakpoint(overlay_loader).location then call warning('breakpoint already set at that location is being replaced'); else go to overlay_set; /*breakpoint by octal address on overlay loader requires special treatment*/ end; else do; ibpt = find_breakpoint(0, 0); /*find an unused slot*/ if ibpt = bpt_not_found then call error('breakpoint table full, breakpoint(s) not set'); if (statement_address = userpc) & (statement_overlay = userbreakoverlay) then call warning('breakpoint restored at current break location'); breakpoint(ibpt).overlay = statement_overlay; breakpoint(ibpt).location = statement_address; breakpoint(ibpt).instruction = to_be_determined; if overlay_mapped(breakpoint(ibpt).overlay) then call set_a_break(ibpt); if breakpoint(ibpt).overlay ^= root_segment_descriptor /*i.e., if it is in an overlay*/ then do; overlay_set: if overlay_breakpoints = 0 then call set_a_break(overlay_loader); overlay_breakpoints = overlay_breakpoints + 1; end; breakpoint(ibpt).module = statement_module; breakpoint(ibpt).prolog = statement_prolog; /***temp for finding statement address at overlay loader time*/ end; breakpoint(ibpt).to_be_cancelled = false; breakpoint(ibpt).statementn = statement_number; breakpoint(ibpt).aftercount = tname; breakpoint(ibpt).do_number = 0; breakpoint(ibpt).do_fileaddr = null_fileaddr; end; if nxtokenis('DO') then do; if debprocedure_define_level = 0 then do; /*initializing do group*/ last_do_number = last_do_number + 1; breakpoint(ibpt).do_number = last_do_number; call workput('DO'!!trim(last_do_number), debprocedure_class, dogroup_subclass); debprocedure_startp = nextp+1; /*for skipping the DO & following character (presumed to be semicolon or blank) also used by error to allow re-entering first line on error*/ call workwrite(substr(commandline,tokenp,debprocedure_startp-tokenp)); /*write the DO separately*/ breakpoint(ibpt).do_fileaddr = current_fileaddr(workfile); /*save location of text for direct access on break*/ work_debprocedure_line_pos = breakpoint(ibpt).do_fileaddr; /*also save for re-entering line on error*/ call workwrite(substr(commandline,debprocedure_startp)); /*write first line of DO-group, less the DO*/ end; debprocedure_define_level = debprocedure_define_level + 1; goto command_done; end; if nxtokenis(';') then goto command_done; if ^nxtokenis(',') then call error('missing comma, or incorrect syntax for a set breakpoint list'); goto setbreaknext; end; return; command_done: signal condition(endcmd); end; /* PL/I symbolic debugger procedure to search the breakpoint table called from breakcmd and gocmd %include 'findbpt.inc' to get proper declarations */ find_breakpoint: procedure(loc, ovly) returns(fixed bin(15)); dcl (loc, ovly, ibpt) fixed bin(15); %include 'breakdef.pli'; %include 'findbpt.inc'; /*for bpt_not_found*/ /**************************************************************************************************************/ do ibpt = lbound(breakpoint,1) to hbound(breakpoint,1); if loc = breakpoint(ibpt).location & ovly = breakpoint(ibpt).overlay then return(ibpt); end; return(bpt_not_found); end; /* PL/I symbolic debugger procedure for bottom-level set a breakpoint logic. called by SET BREAK in breakcmd to set user breakpoint & breakpoint in overlay loader, and from overlay loader breakpoint in gocmd (**temp, for deferred set). when .SYM file has statement number table, this procedure can move back to being local to breakcmd */ set_a_break: procedure(ibpt); dcl ibpt fixed bin(15); /*subscript in breakpoint array*/ %include 'breakdef.pli'; %include 'getword.inc'; %include 'putword.inc'; %include 'truefalse.inc'; dcl ( bpt_instruction, psTbit ) fixed bin(15) external; /*defined in debasm*/ dcl (ibpt_location, i) fixed bin(15); /**************************************************************************************************************/ ibpt_location = breakpoint(ibpt).location; if breakpoint(ibpt).instruction = to_be_determined then breakpoint(ibpt).instruction = getword(ibpt_location); call putword(ibpt_location, bpt_instruction); /*flag all breakpoints at same address as unmapped so when we hit one we can tell which it is*/ do i = lbound(breakpoint,1) to hbound(breakpoint,1); if breakpoint(i).location = ibpt_location then breakpoint(i).overlay_unmapped = true; end; breakpoint(ibpt).overlay_unmapped = false; /*we are only called if it's mapped*/ end; /* PL/I symbolic debugger procedure for bottom level cancel break logic. called by CANCEL BREAK in breakcmd and from overlay loader breakpoint in gocmd (**temp, for deferred cancel). when .SYM file has statement number table, this procedure can move back to being local to breakcmd */ cancel_a_break: procedure(ibpt); dcl ibpt fixed bin(15); /*subscript in breakpoint array*/ %include 'segdef.pli'; /*for root_segment_descriptor*/ %include 'breakdef.pli'; %include 'putword.inc'; %include 'truefalse.inc'; dcl ovly fixed bin(15); /**************************************************************************************************************/ if ibpt = overlay_loader then do; if breakpoint(overlay_loader).to_be_cancelled then return; /*dont touch implicit overlay loader breakpoint*/ /*breakpoint by octal address on overlay loader requires special treatment*/ breakpoint(overlay_loader).to_be_cancelled = true; /*set flag to inhibit showing on SHOW BREAK*/ go to overlay_cancel; end; call putword(breakpoint(ibpt).location, breakpoint(ibpt).instruction); ovly = breakpoint(ibpt).overlay; breakpoint(ibpt).location = 0; breakpoint(ibpt).overlay = 0; if ovly ^= root_segment_descriptor /*i.e., if it is in an overlay*/ then do; overlay_cancel: overlay_breakpoints = overlay_breakpoints - 1; if overlay_breakpoints = 0 /*if no more breakpoints in overlays, cancel bpt in loader*/ then call putword(breakpoint(overlay_loader).location, breakpoint(overlay_loader).instruction); end; end;