1/*
2 * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot.debugger.windbg;
26
27import sun.jvm.hotspot.debugger.*;
28import sun.jvm.hotspot.debugger.win32.coff.*;
29import sun.jvm.hotspot.debugger.cdbg.*;
30import sun.jvm.hotspot.utilities.Assert;
31import sun.jvm.hotspot.utilities.memo.*;
32
33/** Provides a simple wrapper around the COFF library which handles
34    relocation. A DLL can represent either a DLL or an EXE file. */
35
36public class DLL implements LoadObject {
37
38  public DLL(WindbgDebugger dbg, String filename, long size, Address relocation) throws COFFException {
39    this.dbg     = dbg;
40    fullPathName = filename;
41    this.size    = size;
42    file = new MemoizedObject() {
43        public Object computeValue() {
44          return COFFFileParser.getParser().parse(fullPathName);
45        }
46      };
47    addr = relocation;
48  }
49
50  /** This constructor was originally used to fetch the DLL's name out
51      of the target process to match it up with the known DLL names,
52      before the fetching of the DLL names and bases was folded into
53      one command. It is no longer used. If it is used, getName() will
54      return null and getSize() will return 0. */
55  public DLL(Address base) throws COFFException {
56    this.addr = base;
57    file = new MemoizedObject() {
58        public Object computeValue() {
59          return COFFFileParser.getParser().parse(new AddressDataSource(addr));
60        }
61      };
62  }
63
64  /** Indicates whether this is really a DLL or actually a .EXE
65      file. */
66  public boolean isDLL() {
67    return getFile().getHeader().hasCharacteristic(Characteristics.IMAGE_FILE_DLL);
68  }
69
70  /** Look up a symbol; returns absolute address or null if symbol was
71      not found. */
72  public Address lookupSymbol(String symbol) throws COFFException {
73    if (!isDLL()) {
74      return null;
75    }
76    ExportDirectoryTable exports = getExportDirectoryTable();
77    return lookupSymbol(symbol, exports,
78                        0, exports.getNumberOfNamePointers() - 1);
79  }
80
81  public Address getBase() {
82    return addr;
83  }
84
85  /** Returns the full path name of this DLL/EXE, or null if this DLL
86      object was created by parsing the target process's address
87      space. */
88  public String getName() {
89    return fullPathName;
90  }
91
92  public long getSize() {
93    return size;
94  }
95
96  public CDebugInfoDataBase getDebugInfoDataBase() throws DebuggerException {
97    if (db != null) {
98      return db;
99    }
100
101    // Try to parse
102    if (dbg == null) {
103      return null; // Need WindbgDebugger
104    }
105
106    if (Assert.ASSERTS_ENABLED) {
107      Assert.that(fullPathName != null, "Need full path name to build debug info database");
108    }
109
110    db = new WindbgCDebugInfoBuilder(dbg).buildDataBase(fullPathName, addr);
111    return db;
112  }
113
114  public BlockSym debugInfoForPC(Address pc) throws DebuggerException {
115    CDebugInfoDataBase db = getDebugInfoDataBase();
116    if (db == null) {
117      return null;
118    }
119    return db.debugInfoForPC(pc);
120  }
121
122  public ClosestSymbol closestSymbolToPC(Address pcAsAddr) throws DebuggerException {
123    ExportDirectoryTable exports = getExportDirectoryTable();
124    if (exports == null) {
125      return null;
126    }
127    String name = null;
128    long   pc   = dbg.getAddressValue(pcAsAddr);
129    long   diff = Long.MAX_VALUE;
130    long   base = dbg.getAddressValue(addr);
131    for (int i = 0; i < exports.getNumberOfNamePointers(); i++) {
132      if (!exports.isExportAddressForwarder(exports.getExportOrdinal(i))) {
133        long tmp = base + (exports.getExportAddress(exports.getExportOrdinal(i)) & 0xFFFFFFFF);
134        if ((tmp <= pc) && ((pc - tmp) < diff)) {
135          diff = pc - tmp;
136          name = exports.getExportName(i);
137        }
138      }
139    }
140    if (name == null) {
141      return null;
142    }
143    return new ClosestSymbol(name, diff);
144  }
145
146  public LineNumberInfo lineNumberForPC(Address pc) throws DebuggerException {
147    CDebugInfoDataBase db = getDebugInfoDataBase();
148    if (db == null) {
149      return null;
150    }
151    return db.lineNumberForPC(pc);
152  }
153
154  public void close() {
155    getFile().close();
156    file = null;
157  }
158
159  //----------------------------------------------------------------------
160  // Internals only below this point
161  //
162
163  private COFFFile getFile() {
164    return (COFFFile) file.getValue();
165  }
166
167  private Address lookupSymbol(String symbol, ExportDirectoryTable exports,
168                               int loIdx, int hiIdx) {
169    do {
170      int curIdx = ((loIdx + hiIdx) >> 1);
171      String cur = exports.getExportName(curIdx);
172      if (symbol.equals(cur)) {
173        return addr.addOffsetTo(
174          ((long) exports.getExportAddress(exports.getExportOrdinal(curIdx))) & 0xFFFFFFFFL
175        );
176      }
177      if (symbol.compareTo(cur) < 0) {
178        if (hiIdx == curIdx) {
179          hiIdx = curIdx - 1;
180        } else {
181          hiIdx = curIdx;
182        }
183      } else {
184        if (loIdx == curIdx) {
185          loIdx = curIdx + 1;
186        } else {
187          loIdx = curIdx;
188        }
189      }
190    } while (loIdx <= hiIdx);
191
192    return null;
193  }
194
195  private ExportDirectoryTable getExportDirectoryTable() {
196    return
197      getFile().getHeader().getOptionalHeader().getDataDirectories().getExportDirectoryTable();
198  }
199
200  private WindbgDebugger  dbg;
201  private String         fullPathName;
202  private long           size;
203  // MemoizedObject contains a COFFFile
204  private MemoizedObject file;
205  // Base address of module in target process
206  private Address        addr;
207  // Debug info database for this DLL
208  private CDebugInfoDataBase db;
209}
210