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.proc.live;
041    
042    import inua.eio.ByteBuffer;
043    import frysk.sys.Errno;
044    import frysk.sys.ProcessIdentifier;
045    import frysk.sys.ptrace.AddressSpace;
046    import frysk.sys.proc.Mem;
047    import frysk.event.Request;
048    import frysk.proc.Manager;
049    
050    public class AddressSpaceByteBuffer extends ByteBuffer {
051        protected final AddressSpace addressSpace;
052        protected final ProcessIdentifier pid;
053    
054        // Direct files access if possible, or null otherwise.
055        private Mem mem;
056    
057        protected AddressSpaceByteBuffer (ProcessIdentifier pid,
058                                          AddressSpace addressSpace,
059                                          long lowerExtreem, long upperExtreem) {
060            super (lowerExtreem, upperExtreem);
061            this.pid = pid;
062            this.addressSpace = addressSpace;
063            peekRequest = new PeekRequest();
064            pokeRequest = new PokeRequest();
065            if (addressSpace == AddressSpace.TEXT
066                || addressSpace == AddressSpace.DATA)
067                // Try to use /proc; but if any error occures clear it and
068                // revert back to ptrace.
069                mem = new Mem(pid);
070        }
071        public AddressSpaceByteBuffer(ProcessIdentifier pid,
072                                      AddressSpace addressSpace) {
073            this(pid, addressSpace, 0, addressSpace.length());
074        }
075    
076    
077        private class PeekRequest
078            extends Request
079        {
080            private long index;
081            private int value;
082            PeekRequest()
083            {
084                super(Manager.eventLoop);
085            }
086            public void execute ()
087            {
088                value = addressSpace.peek(pid, index);
089            }
090            public int request (long index)
091            {
092                if (isEventLoopThread())
093                    return addressSpace.peek(pid, index);
094                else synchronized (this) {
095                    this.index = index;
096                    request();
097                    return value;
098                }
099            }
100        }
101        private final PeekRequest peekRequest;
102        protected int peek(long index) {
103            return peekRequest.request (index);
104        }
105    
106        private class PokeRequest
107            extends Request
108        {
109            private long index;
110            private int value;
111            PokeRequest()
112            {
113                super(Manager.eventLoop);
114            }
115            public void execute ()
116            {
117                addressSpace.poke(pid, index, value);
118            }
119            public void request (long index, int value)
120            {
121                if (isEventLoopThread())
122                    addressSpace.poke(pid, index, value);
123                else synchronized (this) {
124                    this.index = index;
125                    this.value = value;
126                    request();
127                }
128            }
129        }
130        private final PokeRequest pokeRequest;
131        protected void poke(long index, int value) {
132            pokeRequest.request (index, value);
133        }
134    
135        private class TransferRequest extends Request {
136            private long index;
137            private byte[] bytes;
138            private int offset;
139            private int length;
140            private boolean write;
141            TransferRequest() {
142                super(Manager.eventLoop);
143            }
144            private void transfer(long index, byte[] bytes, int offset, int length,
145                                  boolean write) {
146                if (mem != null && !write) {
147                    try {
148                        mem.pread(index, bytes, offset, length);
149                        return;
150                    } catch (Errno e) {
151                        // Give up on mem; and fall back to ptrace.  This
152                        // can happen when /proc isn't mounted, or when a
153                        // process is terminating and the kernel scrubs
154                        // the /proc entry before its time.
155                        mem = null;
156                    }
157                }
158                addressSpace.transfer(pid, index, bytes, offset, length,
159                                      write);
160            }
161    
162            public void execute() {
163                transfer(index, bytes, offset, length, write);
164            }
165    
166            public void request(long index, byte[] bytes, int offset, int length,
167                                boolean write) {
168                if (isEventLoopThread())
169                    transfer(index, bytes, offset, length, write);
170                else synchronized (this) {
171                    this.index = index;
172                    this.bytes = bytes;
173                    this.offset = offset;
174                    this.length = length;
175                    this.write = write;
176                    super.request();
177                }
178            }
179        }
180        private final TransferRequest transfer = new TransferRequest();
181    
182        protected int peek(long index, byte[] bytes, int offset, int length) {
183            transfer.request(index, bytes, offset, length, false); // read
184            return length;
185        }
186        protected int poke(long index, byte[] bytes, int offset, int length) {
187            transfer.request(index, bytes, offset, length, true); // write
188            return length;
189        }
190    
191        protected ByteBuffer subBuffer (ByteBuffer parent, long lowerExtreem,
192                                        long upperExtreem)
193        {
194            AddressSpaceByteBuffer up = (AddressSpaceByteBuffer)parent;
195            return new AddressSpaceByteBuffer (up.pid, up.addressSpace,
196                                               lowerExtreem, upperExtreem);
197        }
198    }