001    // This file is part of the program FRYSK.
002    //
003    // Copyright 2007, 2008, Red Hat Inc.
004    //
005    // FRYSK is free software; you can redistribute it and/or modify it
006    // under the terms of the GNU General Public License as published by
007    // the Free Software Foundation; version 2 of the License.
008    //
009    // FRYSK is distributed in the hope that it will be useful, but
010    // WITHOUT ANY WARRANTY; without even the implied warranty of
011    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012    // General Public License for more details.
013    // 
014    // You should have received a copy of the GNU General Public License
015    // along with FRYSK; if not, write to the Free Software Foundation,
016    // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
017    // 
018    // In addition, as a special exception, Red Hat, Inc. gives You the
019    // additional right to link the code of FRYSK with code not covered
020    // under the GNU General Public License ("Non-GPL Code") and to
021    // distribute linked combinations including the two, subject to the
022    // limitations in this paragraph. Non-GPL Code permitted under this
023    // exception must only link to the code of FRYSK through those well
024    // defined interfaces identified in the file named EXCEPTION found in
025    // the source code files (the "Approved Interfaces"). The files of
026    // Non-GPL Code may instantiate templates or use macros or inline
027    // functions from the Approved Interfaces without causing the
028    // resulting work to be covered by the GNU General Public
029    // License. Only Red Hat, Inc. may make changes or additions to the
030    // list of Approved Interfaces. You must obey the GNU General Public
031    // License in all respects for all of the FRYSK code and other code
032    // used in conjunction with FRYSK except the Non-GPL Code covered by
033    // this exception. If you modify this file, you may extend this
034    // exception to your version of the file, but you are not obligated to
035    // do so. If you do not wish to provide this exception without
036    // modification, you must delete this exception statement from your
037    // version and license this file solely under the GPL without
038    // exception.
039    
040    package frysk.rt;
041    
042    import java.util.Iterator;
043    import frysk.rsl.Log;
044    import frysk.proc.Action;
045    import frysk.proc.Observable;
046    import frysk.proc.Task;
047    import frysk.proc.TaskObserver;
048    import frysk.stepping.SteppingEngine;
049    
050    public class Breakpoint implements TaskObserver.Code {
051        private static final Log fine = Log.fine(Breakpoint.class);
052    
053        protected long address;
054    
055        protected int triggered;
056    
057        protected boolean added;
058    
059        protected boolean removed;
060    
061        protected Object monitor = new Object();
062    
063        protected SteppingEngine steppingEngine;
064    
065        public Breakpoint (SteppingEngine steppingEngine) {
066            this.steppingEngine = steppingEngine;
067        }
068    
069        public Breakpoint (SteppingEngine steppingEngine, long address) {
070            //    System.out.println("Setting address to 0x" + Long.toHexString(address));
071            this.steppingEngine = steppingEngine;
072            this.address = address;
073        }
074    
075        public Action updateHit (Task task, long address) {
076    
077            fine.log(this, "updateHit task", task, "address", address);
078            if (address != this.address) {
079                fine.log(this, "updateHit task", task, "address", address,
080                         "wrong address!");
081                return Action.CONTINUE;
082            }
083            else {
084                fine.log(this, "updateHit calling blockedByActionPoint", task,
085                         "address", address);           
086                this.steppingEngine.blockedByActionPoint(task, this);
087                task.requestUnblock(this);
088            }
089    
090            ++triggered;
091            return Action.BLOCK;
092        }
093    
094        public int getTriggered () {
095            return triggered;
096        }
097    
098        public void addFailed (Object observable, Throwable w) {
099            w.printStackTrace();
100        }
101    
102        public void addedTo (Object observable) {
103            synchronized (monitor) {
104                added = true;
105                removed = false;
106                monitor.notifyAll();
107            }
108            //    System.err.println("BreakPoint.addedTo");
109            ((Task) observable).requestDeleteInstructionObserver(this.steppingEngine.getSteppingObserver());
110        }
111    
112        public boolean isAdded () {
113            return added;
114        }
115    
116        public void deletedFrom (Object observable) {
117            synchronized (monitor) {
118                removed = true;
119                added = false;
120                monitor.notifyAll();
121            }
122        }
123    
124        public boolean isRemoved () {
125            return removed;
126        }
127    
128        public long getAddress() {
129            return address;
130        }
131    
132        static public class PersistentBreakpoint extends Breakpoint {
133    
134            /*
135             * A breakpoint added by a high-level action e.g., set by the
136             * user. It is not meant to be transient and applies only to one task.
137             */
138            private Observable observable;
139            private final Task targetTask;
140    
141            public Task getTargetTask() {
142                return targetTask;
143            }
144    
145            public PersistentBreakpoint(Task targetTask, long address,
146                                        SteppingEngine steppingEngine) {
147                super(steppingEngine, address);
148                observable = new Observable(this);
149                this.targetTask = targetTask;
150            }
151    
152            // These operations synchronize on the breakpoint, not the
153            // observable object, so that other users of PersistentBreakpoint
154            // can synchronize too without having to make the observable public.
155            public synchronized void addObserver(BreakpointObserver observer) {
156                observable.add(observer);
157            }
158    
159            public synchronized void deleteObserver(BreakpointObserver observer) {
160                observable.delete(observer);
161            }
162    
163            public Iterator observersIterator() {
164                return observable.iterator();
165            }
166    
167            public synchronized int numberOfObservers() {
168                return observable.numberOfObservers();
169            }
170    
171            public synchronized void removeAllObservers() {
172                observable.removeAllObservers();
173            }
174    
175            public Action updateHit(Task task, long address) {
176                if (task != targetTask)
177                    return Action.CONTINUE;
178                fine.log(this, "updateHit task", task, "address", address);
179                Action action = super.updateHit(task, address);
180    
181                synchronized (SteppingEngine.class) {
182                    steppingEngine.getRunningTasks().remove(task);
183                }
184    
185                synchronized (this) {
186                    Iterator iterator = observable.iterator();
187                    while (iterator.hasNext()) {
188                        BreakpointObserver observer
189                            = (BreakpointObserver)iterator.next();
190                        observer.updateHit(this, task, address);
191                    }
192                }
193                return action;
194            }
195    
196            public void addedTo (Object observable) {
197                synchronized (monitor) {
198                    added = true;
199                    removed = false;
200                    monitor.notifyAll();
201                }
202                // Don't remove the current insturction observer.
203            }
204        }
205    
206        //    public PersistentBreakpoint getTaskPersistentBreakpoint(Task task)
207        //    {
208        //      return (PersistentBreakpoint) SteppingEngine.getTaskBreakpoint(task);
209        //    }
210    
211        public void addPersistentBreakpoint(Task task, PersistentBreakpoint bp) {
212            task.requestAddCodeObserver(bp, bp.getAddress());
213        }
214    
215        public void deletePersistentBreakpoint(Task task, PersistentBreakpoint bp) {
216            task.requestDeleteCodeObserver(bp, bp.getAddress());
217        }
218    }