mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
Merge
This commit is contained in:
commit
4bac80d151
11285 changed files with 1571898 additions and 185033 deletions
|
@ -3,3 +3,4 @@
|
|||
/nbproject/private/
|
||||
^webrev
|
||||
^.hgtip
|
||||
.DS_Store
|
||||
|
|
33
.hgtags
33
.hgtags
|
@ -121,3 +121,36 @@ f4298bc3f4b6baa315643be06966f09684290068 jdk7-b140
|
|||
07a8728ad49ef6dfa469c3a8bf5ab1e9c80bed5c jdk7-b144
|
||||
8294c99e685a1f6d1d37c45cd97854cf74be771e jdk7-b145
|
||||
dca1e8a87e8f756f95b99bac8fe795750d42e1b0 jdk7-b146
|
||||
a2a589fc29543ed32919c78a1810ad93a6fcf5bc jdk7-b147
|
||||
de9223c94f9c710b3eebb599cd3586f36c8b94a9 jdk8-b01
|
||||
1b9d19620eb4606a25b1e28f86d66c8bfa867e06 jdk8-b02
|
||||
6815e85bf96d6d3875954f9777660372cd70d065 jdk8-b03
|
||||
31f5c34d78081572ad9a2401c0bb0c6b9711dd65 jdk8-b04
|
||||
c4f9ea1ecb55ff44e0dd21d2888ead308c86a3aa jdk8-b05
|
||||
429da7734bf491bccde2a752fae97e9f225896dc jdk8-b06
|
||||
bc5710332b294676661103bb20d47d2ea3ba8def jdk8-b07
|
||||
24ee504f80412770c6874836cd9e55b536427b1d jdk8-b08
|
||||
fbf3cabc9e3bb1fcf710941d777cb0400505fbe6 jdk8-b09
|
||||
f651ce87127980c58e3599daba964eba2f3b4026 jdk8-b10
|
||||
cc1f5ce8e504d350e0b0c28c5f84333f8d540132 jdk8-b11
|
||||
86db042b3385c338e17f7664447fdc7d406dd19e jdk8-b12
|
||||
4cc0ef72c812943743ef4765f1100e2fbe2b1a08 jdk8-b13
|
||||
9ffaa48dbfb0f5936c2b789867d0785faec7071d jdk8-b14
|
||||
b5060eae3b32fd9f884a09774338cd8186d7fafa jdk8-b15
|
||||
736a63b854f321c7824b7e47890135f80aee05e3 jdk8-b16
|
||||
f0eccb2946986fb9626efde7d8ed9c8192623f5c jdk8-b17
|
||||
885050364691ac1ac978305c63f3368a197fb04d jdk8-b18
|
||||
0ff7113a0882ec82d642cb9f0297b4e497807ced jdk8-b19
|
||||
6561530ea757c3f3a6fb171c9cc7b3885cdeca85 jdk8-b20
|
||||
b3a426170188f52981cf4573a2f14d487fddab0d jdk8-b21
|
||||
e8f03541af27e38aafb619b96863e17f65ffe53b jdk8-b22
|
||||
498124337041ad53cbaa7eb110f3d7acd6d4eac4 jdk8-b23
|
||||
7d3720d8c595d1519c31e9ff7366203fc2c61350 jdk8-b24
|
||||
0071a6d64113a35ba345bb1580c256de5ce17d3e jdk8-b25
|
||||
6c805d8ed4e5449ea5e4d158c7bdbd7b0b70efd1 jdk8-b26
|
||||
c51754cddc037b9609e202b9ed38363d8683e7a8 jdk8-b27
|
||||
16ba58282d117247f480aae7a79b88141ade52a3 jdk8-b28
|
||||
e070119aa56ee4dc5506c19d2c4d2eecab8ad429 jdk8-b29
|
||||
23da7804aca0c9c4e6e86532a1453125a76d95ee jdk8-b30
|
||||
bac81e9f7d57b75fba5ab31b571f3fe0dc08af69 jdk8-b31
|
||||
2c5208ccb863db936eab523f49450b3fcd230348 jdk8-b32
|
||||
|
|
|
@ -121,3 +121,36 @@ cfbbdb77eac0397b03eb99ee2e07ea00e0a7b81e jdk7-b142
|
|||
7203965666a4fe63bf82f5e4204f41ce6285e716 jdk7-b144
|
||||
55e9ebf032186c333e5964ed044419830ac02693 jdk7-b145
|
||||
2d38c2a79c144c30cd04d143d83ee7ec6af40771 jdk7-b146
|
||||
d91364304d7c4ecd34caffdba2b840aeb0d10b51 jdk7-b147
|
||||
f42e3d9394b40a423d345b8da22687b5462e5f25 jdk8-b01
|
||||
69f592185747226a9c765a9fe139c1d34d616f9c jdk8-b02
|
||||
587bb549dff83131b65f40aa51864f69562f34a7 jdk8-b03
|
||||
0b66a233bfb9ba2ebda1e5cdfdb0373d6c1e3c69 jdk8-b04
|
||||
b910aac18c772b823b1f7da03e2c6528725cc6de jdk8-b05
|
||||
28cf2aec4dd7c3c75efc1c15078522467c781a6d jdk8-b06
|
||||
0db7ae9f2b1017124c779bccd016c976928859a0 jdk8-b07
|
||||
fb1bc13260d76447e269e843859eb593fe2a8ab2 jdk8-b08
|
||||
8adb70647b5af5273dfe6a540f07be667cd50216 jdk8-b09
|
||||
a6c4c248e8fa350c35014fa94bab5ac1a1ac3299 jdk8-b10
|
||||
1defbc57940a56f0aa41e9dee87b71e8c8b71103 jdk8-b11
|
||||
8e2104d565baee473895d5eba20e39f85ab4bf9f jdk8-b12
|
||||
26fb81a1e9ceb9baffba216acd9ded62e9e9d5ab jdk8-b13
|
||||
23aa7f2c80a2fa354c80decf03e7c2018177ef4e jdk8-b14
|
||||
a4f28069d44a379cda99dd1d921d19f819726d22 jdk8-b15
|
||||
4e06ae613e99549835896720c7a68c29ad5543f5 jdk8-b17
|
||||
4e06ae613e99549835896720c7a68c29ad5543f5 jdk8-b16
|
||||
7010bd24cdd07bc7daef80702f39124854dec36c jdk8-b18
|
||||
237bc29afbfc6f56a4fe4a6008e2befb59c44bac jdk8-b19
|
||||
5a5eaf6374bcbe23530899579fed17a05b7705f3 jdk8-b20
|
||||
cc771d92284f71765eca14d6d08703c4af254c04 jdk8-b21
|
||||
7ad075c809952e355d25030605da6af30456ed74 jdk8-b22
|
||||
60d6f64a86b1e511169d264727f6d51415978df0 jdk8-b23
|
||||
1a5f1d6b98d6827cdb529a4abe6e52a886d944f4 jdk8-b24
|
||||
221a378e06a326f45e5d89e2123cd6323e0181d1 jdk8-b25
|
||||
2accafff224ae39caf5f532c305251ba624bf2c0 jdk8-b26
|
||||
1533dfab9903e4edcfead3b0192643f38c418b9b jdk8-b27
|
||||
6e2541d60f4e342b5b67140271d7611643929dc3 jdk8-b28
|
||||
41460de042580bc4a4ce3f863779c66f39cb8578 jdk8-b29
|
||||
6cea54809b51db92979c22fd8aa8fcb1cb13d12e jdk8-b30
|
||||
0b66f43b89a6c0ac1c15d7ec51992c541cdc9089 jdk8-b31
|
||||
88176171e940f02916a312c265a34c32552a8376 jdk8-b32
|
||||
|
|
|
@ -1 +1 @@
|
|||
project=jdk7
|
||||
project=jdk8
|
||||
|
|
15
README
15
README
|
@ -9,11 +9,14 @@ README:
|
|||
will be needed.
|
||||
|
||||
This one root repository can be obtained with something like:
|
||||
hg clone http://hg.openjdk.java.net/jdk7/jdk7 openjdk7
|
||||
To make sure you have all the nested repositories, you can run:
|
||||
cd openjdk7 && sh ./get_source.sh
|
||||
(This is identical to using the Mercurial Forest Extension command
|
||||
'hg fclone http://hg.openjdk.java.net/jdk7/jdk7 openjdk7').
|
||||
|
||||
hg clone http://hg.openjdk.java.net/jdk8/jdk8 openjdk8
|
||||
|
||||
To make sure you have all the nested repositories, you can run the
|
||||
get_source.sh script located in the same respository as this file:
|
||||
|
||||
cd openjdk8 && sh ./get_source.sh
|
||||
|
||||
People unfamiliar with Mercurial should read the first few chapters of
|
||||
the Mercurial book: http://hgbook.red-bean.com/read/
|
||||
|
||||
|
@ -22,7 +25,7 @@ README:
|
|||
Simple Build Instructions:
|
||||
|
||||
0. Get the necessary system software/packages installed on your system, see
|
||||
http://hg.openjdk.java.net/jdk7/build/raw-file/tip/README-builds.html
|
||||
http://hg.openjdk.java.net/jdk8/build/raw-file/tip/README-builds.html
|
||||
|
||||
1. If you don't have a jdk6 installed, download and install a JDK 6 from
|
||||
http://java.sun.com/javase/downloads/index.jsp
|
||||
|
|
|
@ -126,38 +126,15 @@
|
|||
<a href="http://openjdk.java.net/guide/repositories.html#installConfig">
|
||||
Developer Guide: Installing and Configuring Mercurial</a>
|
||||
section for more information.
|
||||
The Forest Extension is not part of the Mercurial install,
|
||||
and is optional,
|
||||
but can be obtained with the following commands:
|
||||
<blockquote>
|
||||
<tt>
|
||||
hg clone https://bitbucket.org/pmezard/hgforest-crew/overview/ <i>YourHgForest</i>
|
||||
</tt>
|
||||
</blockquote>
|
||||
Once you have the file <tt>forest.py</tt>, you need to add these
|
||||
lines to your <tt>${HOME}/.hgrc</tt> file:
|
||||
<blockquote>
|
||||
<tt>
|
||||
[extensions]
|
||||
<br>forest = <i>YourHgForest</i>/forest.py
|
||||
</tt>
|
||||
</blockquote>
|
||||
|
||||
<!-- ------------------------------------------------------ -->
|
||||
<h3><a name="get_source">Getting the Source</a></h3>
|
||||
<blockquote>
|
||||
To get the entire set of OpenJDK Mercurial repositories
|
||||
using the Forest Extension:
|
||||
use the script <code>get_source.sh</code> located in the root repository:
|
||||
<blockquote>
|
||||
<tt>
|
||||
hg fclone http://hg.openjdk.java.net/jdk7/jdk7 <i>YourOpenJDK</i>
|
||||
</tt>
|
||||
</blockquote>
|
||||
To get the entire set of OpenJDK Mercurial repositories
|
||||
without using the Forest Extension:
|
||||
<blockquote>
|
||||
<tt>
|
||||
hg clone http://hg.openjdk.java.net/jdk7/jdk7 <i>YourOpenJDK</i>
|
||||
hg clone http://hg.openjdk.java.net/jdk8/jdk8 <i>YourOpenJDK</i>
|
||||
<br>cd <i>YourOpenJDK</i>
|
||||
<br>sh ./get_source.sh
|
||||
</tt>
|
||||
|
@ -172,9 +149,6 @@
|
|||
<br>sh ./make/scripts/hgforest.sh pull -u
|
||||
</tt>
|
||||
</blockquote>
|
||||
You may find this script <tt>make/scripts/hgforest.sh</tt> faster
|
||||
than the <tt>hg</tt> forest commands provided by the
|
||||
Forest Extension.
|
||||
</blockquote>
|
||||
|
||||
</blockquote>
|
||||
|
@ -558,7 +532,7 @@
|
|||
understood that this is not ideal for the open source community.
|
||||
It is possible this process could change in the future.
|
||||
<br>
|
||||
<b>NOTE:</b> The <a href="http://download.java.net/openjdk/jdk7/">
|
||||
<b>NOTE:</b> The <a href="http://download.java.net/openjdk/jdk8/">
|
||||
Complete OpenJDK Source Bundles</a> <u>will</u> contain the JAXP and
|
||||
JAX-WS sources.
|
||||
</p>
|
||||
|
@ -578,7 +552,7 @@
|
|||
</li>
|
||||
<li>
|
||||
The OpenJDK team copies this new bundle into shared
|
||||
area (e.g. <tt>/java/devtools/share/jdk7-drops</tt>).
|
||||
area (e.g. <tt>/java/devtools/share/jdk8-drops</tt>).
|
||||
Older bundles are never deleted so we retain the history.
|
||||
</li>
|
||||
<li>
|
||||
|
@ -1726,7 +1700,7 @@
|
|||
The location of any source drop bundles
|
||||
(see <a href="#drops">Managing the Source Drops</a>).
|
||||
The default will be
|
||||
<tt>$(ALT_JDK_DEVTOOLS_PATH)/share/jdk7-drops</tt>.
|
||||
<tt>$(ALT_JDK_DEVTOOLS_PATH)/share/jdk8-drops</tt>.
|
||||
</dd>
|
||||
<dt><a name="ALT_UNIXCCS_PATH"><tt>ALT_UNIXCCS_PATH</tt></a></dt>
|
||||
<dd>
|
||||
|
@ -1931,7 +1905,7 @@
|
|||
PATH, INCLUDE, LIB, LIBPATH, and WINDOWSSDKDIR
|
||||
variables set in your shell environment.
|
||||
These bat files are not easy to use from a shell environment.
|
||||
However, there is a script placed in the root jdk7 repository called
|
||||
However, there is a script placed in the root jdk8 repository called
|
||||
vsvars.sh that can help, it should only be done once in a shell
|
||||
that will be doing the build, e.g.<br>
|
||||
<tt>sh ./make/scripts/vsvars.sh -v10 > settings<br>
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
^dist/
|
||||
/nbproject/private/
|
||||
^.hgtip
|
||||
.DS_Store
|
||||
|
|
|
@ -122,3 +122,36 @@ a2f340a048c88d10cbedc0504f5cf03d39925a40 jdk7-b142
|
|||
77ec0541aa2aa4da27e9e385a118a2e51e7fca24 jdk7-b145
|
||||
770227a4087e4e401fe87ccd19738440111c3948 jdk7-b146
|
||||
73323cb3396260d93e0ab731fd2d431096ceed0f jdk7-b147
|
||||
949fb60ca830364571e7c4c9964e6b351ca929ec jdk8-b01
|
||||
ed8d94519a87b4adac270c3eec9134ff1f62bff5 jdk8-b02
|
||||
cd0da00694fbce642db9be936d3e4909a71d911d jdk8-b03
|
||||
60a68d688e24473cf84dedd1e60901a61ab82555 jdk8-b04
|
||||
cc1b599b986a37cb57de4584c5e58169766ca535 jdk8-b05
|
||||
45c43dde7ba7f176333a51a98f086275478836fa jdk8-b06
|
||||
3d61f0856f349e2163bf98146465dab3b7437f63 jdk8-b07
|
||||
0d52b1c87aa8fdea7fdc9c4126ea58f95ca6b351 jdk8-b08
|
||||
a891732c1a83082177ff7a4cf1506068d9cc0a47 jdk8-b09
|
||||
cda87f7fefcee3b89742a57ce5ad9b03a54c210d jdk8-b10
|
||||
0199e4fef5cc2bd234c65b93220459ef7a3bb3b1 jdk8-b11
|
||||
31d70911b712c6b4e580a3110363d5f044cfed7a jdk8-b12
|
||||
5b9d9b839d3d7fe02347827221c97c6d242a6f96 jdk8-b13
|
||||
e59c47de1ad8982ff3b0e843773a6902b36c2337 jdk8-b14
|
||||
7da69e7175a7c7564ee6d0e52255cbb8a57ef577 jdk8-b15
|
||||
82dc033975bb9b553b4ef97b6d483eda8de32e0f jdk8-b17
|
||||
82dc033975bb9b553b4ef97b6d483eda8de32e0f jdk8-b16
|
||||
312cf15d16577ef198b033d2a4cc0a52369b7343 jdk8-b18
|
||||
e1366c5d84ef984095a332bcee70b3938232d07d jdk8-b19
|
||||
51d8b6cb18c0978ecfa4f33e1537d35ee01b69fa jdk8-b20
|
||||
f157fc2a71a38ce44007a6f18d5b011824dce705 jdk8-b21
|
||||
a11d0062c445d5f36651c78650ab88aa594bcbff jdk8-b22
|
||||
5218eb256658442b62b05295aafa5b5f35252972 jdk8-b23
|
||||
b98f0e6dddf987df565029a1f58417fc1844c3f3 jdk8-b24
|
||||
e45d6b406d5f91ff5256a5c82456ab1e7eb8becd jdk8-b25
|
||||
79f709a099f40c08f76567fa6d813f9009a69826 jdk8-b26
|
||||
4fffe75e4edd39a2517f10b743941bf94edb143d jdk8-b27
|
||||
2082eb35d49a9c2aab90b8d4fd31cefb7a23b82e jdk8-b28
|
||||
6117395d422682f89d228347e319fcaac7edc729 jdk8-b29
|
||||
4605f8418bf562e78be79b25b6b8a5110281acae jdk8-b30
|
||||
1954151dfae8f73db24e396380f7c02bdd47c486 jdk8-b31
|
||||
5d820cb6b1afd75b619e7fd69e4f2b0eb1d5d6a1 jdk8-b32
|
||||
1e2ac1ea3f6c32a62bf88f3fa330120c30db59cb jdk8-b33
|
||||
|
|
46
corba/make/common/Defs-bsd.gmk
Normal file
46
corba/make/common/Defs-bsd.gmk
Normal file
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
#
|
||||
# Makefile to specify compiler flags for programs and libraries
|
||||
# targeted to BSD. Should not contain any rules.
|
||||
#
|
||||
|
||||
# Warning: the following variables are overriden by Defs.gmk. Set
|
||||
# values will be silently ignored:
|
||||
# CFLAGS (set $(OTHER_CFLAGS) instead)
|
||||
# CPPFLAGS (set $(OTHER_CPPFLAGS) instead)
|
||||
# CXXFLAGS (set $(OTHER_CXXFLAGS) instead)
|
||||
# LDFLAGS (set $(OTHER_LDFAGS) instead)
|
||||
# LDLIBS (set $(EXTRA_LIBS) instead)
|
||||
# LDLIBS_COMMON (set $(EXTRA_LIBS) instead)
|
||||
|
||||
# Get shared JDK settings
|
||||
include $(BUILDDIR)/common/shared/Defs.gmk
|
||||
|
||||
ifndef PLATFORM_SRC
|
||||
PLATFORM_SRC = $(TOPDIR)/src/solaris
|
||||
endif # PLATFORM_SRC
|
||||
|
|
@ -149,8 +149,8 @@ strip_prop_options_clean:
|
|||
# Strip the properties files
|
||||
strip_all_props: $(STRIPPROPERTIES_JARFILE) $(STRIP_PROP_options)
|
||||
@if [ -s $(STRIP_PROP_options) ] ; then \
|
||||
$(ECHO) "$(BOOT_JAVA_CMD) -jar $(STRIPPROPERTIES_JARFILE) -optionsfile $(STRIP_PROP_options)" ; \
|
||||
$(BOOT_JAVA_CMD) -jar $(STRIPPROPERTIES_JARFILE) -optionsfile $(STRIP_PROP_options) ; \
|
||||
$(ECHO) "$(BOOT_JAVA_CMD) -jar $(STRIPPROPERTIES_JARFILE) @$(STRIP_PROP_options)" ; \
|
||||
$(BOOT_JAVA_CMD) -jar $(STRIPPROPERTIES_JARFILE) @$(STRIP_PROP_options) ; \
|
||||
fi
|
||||
@$(java-vm-cleanup)
|
||||
|
||||
|
|
131
corba/make/common/shared/Defs-bsd.gmk
Normal file
131
corba/make/common/shared/Defs-bsd.gmk
Normal file
|
@ -0,0 +1,131 @@
|
|||
#
|
||||
# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
#
|
||||
# Definitions for Bsd.
|
||||
#
|
||||
|
||||
# Default for COMPILER_WARNINGS_FATAL on Bsd (C & C++ compiler warnings)
|
||||
ifndef COMPILER_WARNINGS_FATAL
|
||||
COMPILER_WARNINGS_FATAL=false
|
||||
endif
|
||||
|
||||
# Bsd should use parallel compilation for best build times
|
||||
ifndef COMPILE_APPROACH
|
||||
COMPILE_APPROACH = parallel
|
||||
endif
|
||||
|
||||
# Indication that we are doing an incremental build.
|
||||
# This may trigger the creation of make depend files.
|
||||
ifndef INCREMENTAL_BUILD
|
||||
INCREMENTAL_BUILD = false
|
||||
endif
|
||||
|
||||
# FullPath just makes sure it never ends with a / and no duplicates
|
||||
define FullPath
|
||||
$(shell cd $1 2> $(DEV_NULL) && pwd)
|
||||
endef
|
||||
|
||||
# OptFullPath: Absolute path name of a dir that might not initially exist.
|
||||
define OptFullPath
|
||||
$(shell if [ "$1" != "" -a -d "$1" ]; then (cd $1 && pwd); else echo "$1"; fi)
|
||||
endef
|
||||
|
||||
# Location on system where jdk installs might be
|
||||
USRJDKINSTANCES_PATH =$(PACKAGE_PATH)
|
||||
|
||||
# UNIXCOMMAND_PATH: path to where the most common Unix commands are.
|
||||
# NOTE: Must end with / so that it could be empty, allowing PATH usage.
|
||||
ifneq "$(origin ALT_UNIXCOMMAND_PATH)" "undefined"
|
||||
UNIXCOMMAND_PATH :=$(call PrefixPath,$(ALT_UNIXCOMMAND_PATH))
|
||||
else
|
||||
UNIXCOMMAND_PATH = /bin/
|
||||
endif
|
||||
|
||||
# USRBIN_PATH: path to where the most common Unix commands are.
|
||||
# NOTE: Must end with / so that it could be empty, allowing PATH usage.
|
||||
ifneq "$(origin ALT_USRBIN_PATH)" "undefined"
|
||||
USRBIN_PATH :=$(call PrefixPath,$(ALT_USRBIN_PATH))
|
||||
else
|
||||
USRBIN_PATH = /usr/bin/
|
||||
endif
|
||||
|
||||
# UNIXCCS_PATH: path to where the Solaris ported UNIX commands can be found
|
||||
# NOTE: Must end with / so that it could be empty, allowing PATH usage.
|
||||
ifneq "$(origin ALT_UNIXCCS_PATH)" "undefined"
|
||||
UNIXCCS_PATH :=$(call PrefixPath,$(ALT_UNIXCCS_PATH))
|
||||
else
|
||||
UNIXCCS_PATH = /usr/ccs/bin/
|
||||
endif
|
||||
|
||||
# SLASH_JAVA: location of all network accessable files
|
||||
ifdef ALT_SLASH_JAVA
|
||||
SLASH_JAVA :=$(ALT_SLASH_JAVA)
|
||||
else
|
||||
SLASH_JAVA := $(call DirExists,/java,/java,/NOT-SET)
|
||||
endif
|
||||
|
||||
# JDK_DEVTOOLS_DIR: common path for all the java devtools
|
||||
ifdef ALT_JDK_DEVTOOLS_DIR
|
||||
JDK_DEVTOOLS_DIR =$(ALT_JDK_DEVTOOLS_DIR)
|
||||
else
|
||||
JDK_DEVTOOLS_DIR =$(SLASH_JAVA)/devtools
|
||||
endif
|
||||
|
||||
# DEVTOOLS_PATH: for other tools required for building (such as zip, etc.)
|
||||
# NOTE: Must end with / so that it could be empty, allowing PATH usage.
|
||||
ifneq "$(origin ALT_DEVTOOLS_PATH)" "undefined"
|
||||
DEVTOOLS_PATH :=$(call PrefixPath,$(ALT_DEVTOOLS_PATH))
|
||||
else
|
||||
DEVTOOLS_PATH =$(PACKAGE_PATH)/bin/
|
||||
endif
|
||||
|
||||
# _BOOTDIR1: First choice for a Bootstrap JDK, previous released JDK.
|
||||
# _BOOTDIR2: Second choice
|
||||
ifndef ALT_BOOTDIR
|
||||
_BOOTDIR1 =$(SLASH_JAVA)/re/jdk/$(PREVIOUS_JDK_VERSION)/archive/fcs/binaries/$(PLATFORM)-$(ARCH)
|
||||
_BOOTDIR2 =$(USRJDKINSTANCES_PATH)/jdk$(PREVIOUS_JDK_VERSION)
|
||||
endif
|
||||
|
||||
# Import JDK images allow for partial builds, components not built are
|
||||
# imported (or copied from) these import areas when needed.
|
||||
|
||||
# BUILD_JDK_IMPORT_PATH: location of JDK install trees to import for
|
||||
# multiple platforms, e.g. windows-i586, solaris-sparc, bsd-586, etc.
|
||||
ifdef ALT_BUILD_JDK_IMPORT_PATH
|
||||
BUILD_JDK_IMPORT_PATH :=$(call FullPath,$(ALT_BUILD_JDK_IMPORT_PATH))
|
||||
else
|
||||
BUILD_JDK_IMPORT_PATH = $(PROMOTED_BUILD_BINARIES)
|
||||
endif
|
||||
BUILD_JDK_IMPORT_PATH:=$(call AltCheckValue,BUILD_JDK_IMPORT_PATH)
|
||||
|
||||
# JDK_IMPORT_PATH: location of JDK install tree (this version) to import
|
||||
ifdef ALT_JDK_IMPORT_PATH
|
||||
JDK_IMPORT_PATH :=$(call FullPath,$(ALT_JDK_IMPORT_PATH))
|
||||
else
|
||||
JDK_IMPORT_PATH = $(BUILD_JDK_IMPORT_PATH)/$(PLATFORM)-$(ARCH)$(_JDK_IMPORT_VARIANT)
|
||||
endif
|
||||
JDK_IMPORT_PATH:=$(call AltCheckValue,JDK_IMPORT_PATH)
|
||||
|
|
@ -53,6 +53,13 @@ ifeq ($(PLATFORM),linux)
|
|||
UTILS_DEVTOOL_PATH=$(USRBIN_PATH)
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),bsd)
|
||||
UTILS_COMMAND_PATH=$(UNIXCOMMAND_PATH)
|
||||
UTILS_USR_BIN_PATH=$(USRBIN_PATH)
|
||||
UTILS_CCS_BIN_PATH=$(USRBIN_PATH)
|
||||
UTILS_DEVTOOL_PATH=$(DEVTOOLS_PATH)
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),solaris)
|
||||
UTILS_COMMAND_PATH=$(UNIXCOMMAND_PATH)
|
||||
UTILS_USR_BIN_PATH=$(UNIXCOMMAND_PATH)
|
||||
|
@ -166,15 +173,15 @@ ifeq ($(PLATFORM),linux)
|
|||
# Also, some distribution (Ubuntu, Debian, others?) place the rpm command
|
||||
# itself in /usr/bin rather than it's traditional home in /bin.
|
||||
RPM=$(firstword $(wildcard $(UTILS_COMMAND_PATH)rpm) \
|
||||
$(wildcard $(UTILS_USR_BIN_PATH)rpm))
|
||||
$(wildcard $(UTILS_USR_BIN_PATH)rpm))
|
||||
RPMBUILD=$(firstword $(wildcard $(UTILS_COMMAND_PATH)rpmbuild) \
|
||||
$(wildcard $(UTILS_USR_BIN_PATH)rpmbuild) \
|
||||
$(wildcard $(UTILS_COMMAND_PATH)rpm) \
|
||||
$(wildcard $(UTILS_USR_BIN_PATH)rpm))
|
||||
$(wildcard $(UTILS_USR_BIN_PATH)rpmbuild) \
|
||||
$(wildcard $(UTILS_COMMAND_PATH)rpm) \
|
||||
$(wildcard $(UTILS_USR_BIN_PATH)rpm))
|
||||
# Most Linux distros have "sort" in /bin. Ubuntu, Debian and perhaps
|
||||
# others have it in /usr/bin.
|
||||
SORT=$(firstword $(wildcard $(UTILS_COMMAND_PATH)sort) \
|
||||
$(wildcard $(UTILS_USR_BIN_PATH)sort))
|
||||
$(wildcard $(UTILS_USR_BIN_PATH)sort))
|
||||
NAWK = $(USRBIN_PATH)gawk
|
||||
# Intrinsic unix command, with backslash-escaped character interpretation
|
||||
ECHO = /bin/echo -e
|
||||
|
@ -198,3 +205,34 @@ ifeq ($(PLATFORM),solaris)
|
|||
ECHO = /usr/bin/echo
|
||||
endif
|
||||
|
||||
# BSD specific
|
||||
ifeq ($(PLATFORM),bsd)
|
||||
BASENAME = $(UTILS_USR_BIN_PATH)basename
|
||||
EGREP = $(UTILS_USR_BIN_PATH)egrep
|
||||
EXPR = $(UTILS_COMMAND_PATH)expr
|
||||
FMT = $(UTILS_USR_BIN_PATH)fmt
|
||||
GREP = $(UTILS_USR_BIN_PATH)grep
|
||||
GUNZIP = $(UTILS_USR_BIN_PATH)gunzip
|
||||
ID = $(UTILS_USR_BIN_PATH)id
|
||||
MSGFMT = $(UTILS_DEVTOOL_PATH)msgfmt
|
||||
SED = $(UTILS_USR_BIN_PATH)sed
|
||||
SORT = $(UTILS_USR_BIN_PATH)sort
|
||||
TEST = $(UTILS_COMMAND_PATH)test
|
||||
TOUCH = $(UTILS_USR_BIN_PATH)touch
|
||||
TRUE = $(UTILS_USR_BIN_PATH)true
|
||||
UNAME = $(UTILS_USR_BIN_PATH)uname
|
||||
# BSD OS_VENDOR specific
|
||||
ifeq ($(OS_VENDOR), Apple)
|
||||
NAWK = $(UTILS_USR_BIN_PATH)awk
|
||||
UNZIPSFX = $(UTILS_USR_BIN_PATH)unzipsfx
|
||||
ZIPEXE = $(UTILS_USR_BIN_PATH)zip
|
||||
else
|
||||
UNZIP = $(UTILS_DEVTOOL_PATH)unzip
|
||||
endif
|
||||
ifeq ($(OS_VENDOR), OpenBSD)
|
||||
NAWK = $(UTILS_USR_BIN_PATH)awk
|
||||
else
|
||||
CPIO = $(UTILS_USR_BIN_PATH)cpio
|
||||
TAR = $(UTILS_USR_BIN_PATH)tar
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -231,6 +231,98 @@ ifeq ($(SYSTEM_UNAME), Linux)
|
|||
MB_OF_MEMORY := $(shell free -m | fgrep Mem: | sed -e 's@\ \ *@ @g' | cut -d' ' -f2)
|
||||
endif
|
||||
|
||||
ifeq ($(SYSTEM_UNAME), FreeBSD)
|
||||
PLATFORM = bsd
|
||||
OS_NAME = freebsd
|
||||
OS_VENDOR = FreeBSD
|
||||
REQUIRED_OS_VERSION = 6.0
|
||||
endif
|
||||
|
||||
ifeq ($(SYSTEM_UNAME), Darwin)
|
||||
PLATFORM = bsd
|
||||
OS_NAME = darwin
|
||||
OS_VENDOR = Apple
|
||||
REQUIRED_OS_VERSION = 8.0
|
||||
endif
|
||||
|
||||
ifeq ($(SYSTEM_UNAME), NetBSD)
|
||||
PLATFORM = bsd
|
||||
OS_NAME = netbsd
|
||||
OS_VENDOR = NetBSD
|
||||
REQUIRED_OS_VERSION = 3.0
|
||||
endif
|
||||
|
||||
ifeq ($(SYSTEM_UNAME), OpenBSD)
|
||||
PLATFORM = bsd
|
||||
OS_NAME = openbsd
|
||||
OS_VENDOR = OpenBSD
|
||||
REQUIRED_OS_VERSION = 4.9
|
||||
endif
|
||||
|
||||
# Platform settings specific to BSD
|
||||
ifeq ($(PLATFORM), bsd)
|
||||
OS_VERSION := $(shell uname -r)
|
||||
# Arch and OS name/version
|
||||
mach := $(shell uname -m)
|
||||
archExpr = case "$(mach)" in \
|
||||
i[3-9]86) \
|
||||
echo i586 \
|
||||
;; \
|
||||
sparc64) \
|
||||
echo sparcv9 \
|
||||
;; \
|
||||
sparc*) \
|
||||
echo sparc \
|
||||
;; \
|
||||
x86_64) \
|
||||
echo amd64 \
|
||||
;; \
|
||||
"Power Macintosh") \
|
||||
echo ppc \
|
||||
;; \
|
||||
*) \
|
||||
echo $(mach) \
|
||||
;; \
|
||||
esac
|
||||
ARCH := $(shell $(archExpr) )
|
||||
ARCH_FAMILY := $(ARCH)
|
||||
|
||||
# Darwin x86 builds are i386/amd64 universal.
|
||||
ifeq ($(SYSTEM_UNAME), Darwin)
|
||||
ifneq ($(ARCH), ppc)
|
||||
ARCH=universal
|
||||
endif
|
||||
endif
|
||||
|
||||
# i586, sparc, and ppc are 32 bit, amd64 and sparc64 are 64
|
||||
ifneq (,$(findstring $(ARCH), i586 sparc ppc universal))
|
||||
ARCH_DATA_MODEL=32
|
||||
else
|
||||
ARCH_DATA_MODEL=64
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH), i586)
|
||||
LIBARCH = i386
|
||||
else
|
||||
LIBARCH = $(ARCH)
|
||||
endif
|
||||
|
||||
# Value of Java os.arch property
|
||||
ARCHPROP = $(LIBARCH)
|
||||
|
||||
# Suffix for file bundles used in previous release
|
||||
BUNDLE_FILE_SUFFIX=.tar.gz
|
||||
# Minimum disk space needed as determined by running 'du -sk' on
|
||||
# a fully built workspace.
|
||||
REQUIRED_FREE_SPACE=1500000
|
||||
# How much RAM does this machine have:
|
||||
ifeq ($(OS_VENDOR), OpenBSD)
|
||||
MB_OF_MEMORY=$(shell sysctl -n hw.physmem | awk '{print int($$NF / 1048576); }' )
|
||||
else
|
||||
MB_OF_MEMORY=$(shell (sysctl -n hw.physmem64 2> /dev/null || sysctl -n hw.physmem) | awk '{print int($$NF / 1048576); }' )
|
||||
endif
|
||||
endif
|
||||
|
||||
# Windows with and without CYGWIN will be slightly different
|
||||
ifeq ($(SYSTEM_UNAME), Windows_NT)
|
||||
PLATFORM = windows
|
||||
|
@ -335,8 +427,8 @@ ifeq ($(PLATFORM), windows)
|
|||
MB_OF_MEMORY := $(shell \
|
||||
if [ -f "C:/cygwin/bin/free.exe" ] ; then \
|
||||
( C:/cygwin/bin/bash.exe -c "C:/cygwin/bin/free.exe -m" ) | \
|
||||
grep Mem: | \
|
||||
sed -e 's@\ \ *@ @g' | cut -d' ' -f2 ; \
|
||||
grep Mem: | \
|
||||
sed -e 's@\ \ *@ @g' | cut -d' ' -f2 ; \
|
||||
else \
|
||||
echo "512"; \
|
||||
fi)
|
||||
|
|
|
@ -25,12 +25,23 @@
|
|||
|
||||
# Properties for jprt
|
||||
|
||||
# Use whatever release that the submitted job requests
|
||||
jprt.tools.default.release=${jprt.submit.release}
|
||||
# Locked down to jdk8
|
||||
jprt.tools.default.release=jdk8
|
||||
|
||||
# The different build flavors we want, we override here so we just get these 2
|
||||
jprt.build.flavors=product,fastdebug
|
||||
|
||||
# Standard list of jprt build targets for this source tree
|
||||
jprt.build.targets= \
|
||||
solaris_sparc_5.10-{product|fastdebug}, \
|
||||
solaris_sparcv9_5.10-{product|fastdebug}, \
|
||||
solaris_i586_5.10-{product|fastdebug}, \
|
||||
solaris_x64_5.10-{product|fastdebug}, \
|
||||
linux_i586_2.6-{product|fastdebug}, \
|
||||
linux_x64_2.6-{product|fastdebug}, \
|
||||
windows_i586_5.1-{product|fastdebug}, \
|
||||
windows_x64_5.2-{product|fastdebug}
|
||||
|
||||
# Directories to be excluded from the source bundles
|
||||
jprt.bundle.exclude.src.dirs=build dist webrev
|
||||
|
||||
|
|
|
@ -1,280 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package build.tools.stripproperties;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Reads a properties file from standard input and writes an equivalent
|
||||
* properties file without comments to standard output.
|
||||
*/
|
||||
public class StripProperties {
|
||||
|
||||
private static void error(String msg, Exception e) {
|
||||
System.err.println("ERROR: stripproperties: " + msg);
|
||||
if ( e != null ) {
|
||||
System.err.println("EXCEPTION: " + e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> parseOptions(String args[]) {
|
||||
List<String> files = new ArrayList<String>();
|
||||
for ( int i = 0; i < args.length ; i++ ) {
|
||||
if ( "-optionsfile".equals(args[i]) && i+1 < args.length ) {
|
||||
String filename = args[++i];
|
||||
FileInputStream finput = null;
|
||||
byte contents[] = null;
|
||||
try {
|
||||
finput = new FileInputStream(filename);
|
||||
int byteCount = finput.available();
|
||||
if ( byteCount <= 0 ) {
|
||||
error("The -optionsfile file is empty", null);
|
||||
files = null;
|
||||
} else {
|
||||
contents = new byte[byteCount];
|
||||
int bytesRead = finput.read(contents);
|
||||
if ( byteCount != bytesRead ) {
|
||||
error("Cannot read all of -optionsfile file", null);
|
||||
files = null;
|
||||
}
|
||||
}
|
||||
} catch ( IOException e ) {
|
||||
error("cannot open " + filename, e);
|
||||
files = null;
|
||||
}
|
||||
if ( finput != null ) {
|
||||
try {
|
||||
finput.close();
|
||||
} catch ( IOException e ) {
|
||||
files = null;
|
||||
error("cannot close " + filename, e);
|
||||
}
|
||||
}
|
||||
if ( files != null && contents != null ) {
|
||||
String tokens[] = (new String(contents)).split("\\s+");
|
||||
if ( tokens.length > 0 ) {
|
||||
List<String> ofiles = parseOptions(tokens);
|
||||
if ( ofiles != null ) {
|
||||
files.addAll(ofiles);
|
||||
} else {
|
||||
error("No files found in file", null);
|
||||
files = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( files == null ) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
files.add(args[i]);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private static boolean stripFiles(List<String> files) {
|
||||
boolean ok = true;
|
||||
for ( String file : files ) {
|
||||
|
||||
Properties prop = new Properties();
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new BufferedInputStream(new FileInputStream(file));
|
||||
prop.load(in);
|
||||
} catch ( FileNotFoundException e ) {
|
||||
error("Cannot access file " + file, e);
|
||||
ok = false;
|
||||
} catch ( IOException e ) {
|
||||
error("IO exception processing file " + file, e);
|
||||
ok = false;
|
||||
}
|
||||
if ( in != null ) {
|
||||
try {
|
||||
in.close();
|
||||
} catch ( IOException e ) {
|
||||
error("IO exception closing file " + file, e);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if ( !ok ) {
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(file);
|
||||
storeProperties(prop, out);
|
||||
out.flush();
|
||||
} catch ( IOException e ) {
|
||||
error("IO exception processing file " + file, e);
|
||||
ok = false;
|
||||
}
|
||||
if ( out != null ) {
|
||||
try {
|
||||
out.close();
|
||||
} catch ( IOException e ) {
|
||||
error("IO exception closing file " + file, e);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if ( !ok ) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip the properties filenames supplied, replacing their contents.
|
||||
* @param args Names of properties files to process and replace contents
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
List<String> files = parseOptions(args);
|
||||
if ( files == null || !stripFiles(files) ) {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// --- code below here is adapted from java.util.Properties ---
|
||||
|
||||
private static final String specialSaveChars = "=: \t\r\n\f#!";
|
||||
|
||||
/*
|
||||
* Converts unicodes to encoded \uxxxx
|
||||
* and writes out any of the characters in specialSaveChars
|
||||
* with a preceding slash
|
||||
*/
|
||||
private static String saveConvert(String theString, boolean escapeSpace) {
|
||||
int len = theString.length();
|
||||
StringBuffer outBuffer = new StringBuffer(len*2);
|
||||
|
||||
for(int x=0; x<len; x++) {
|
||||
char aChar = theString.charAt(x);
|
||||
switch(aChar) {
|
||||
case ' ':
|
||||
if (x == 0 || escapeSpace) {
|
||||
outBuffer.append('\\');
|
||||
}
|
||||
outBuffer.append(' ');
|
||||
break;
|
||||
case '\\':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('\\');
|
||||
break;
|
||||
case '\t':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('t');
|
||||
break;
|
||||
case '\n':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('n');
|
||||
break;
|
||||
case '\r':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('r');
|
||||
break;
|
||||
case '\f':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('f');
|
||||
break;
|
||||
default:
|
||||
if ((aChar < 0x0020) || (aChar == 0x007e) || (aChar > 0x00ff)) {
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('u');
|
||||
outBuffer.append(toHex((aChar >> 12) & 0xF));
|
||||
outBuffer.append(toHex((aChar >> 8) & 0xF));
|
||||
outBuffer.append(toHex((aChar >> 4) & 0xF));
|
||||
outBuffer.append(toHex( aChar & 0xF));
|
||||
} else {
|
||||
if (specialSaveChars.indexOf(aChar) != -1) {
|
||||
outBuffer.append('\\');
|
||||
}
|
||||
outBuffer.append(aChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outBuffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of <code>properties</code> to <code>out</code>.
|
||||
* The format is that of Properties.store with the following modifications:
|
||||
* <ul>
|
||||
* <li>No header or date is written
|
||||
* <li>Latin-1 characters are written as single bytes, not escape sequences
|
||||
* <li>Line breaks are indicated by a single \n independent of platform
|
||||
* <ul>
|
||||
*/
|
||||
private static void storeProperties(Properties properties, OutputStream out)
|
||||
throws IOException {
|
||||
BufferedWriter awriter;
|
||||
awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1"));
|
||||
for (Enumeration e = properties.keys(); e.hasMoreElements();) {
|
||||
String key = (String)e.nextElement();
|
||||
String val = (String)properties.get(key);
|
||||
key = saveConvert(key, true);
|
||||
|
||||
/* No need to escape embedded and trailing spaces for value, hence
|
||||
* pass false to flag.
|
||||
*/
|
||||
val = saveConvert(val, false);
|
||||
writeln(awriter, key + "=" + val);
|
||||
}
|
||||
awriter.flush();
|
||||
}
|
||||
|
||||
private static void writeln(BufferedWriter bw, String s) throws IOException {
|
||||
bw.write(s);
|
||||
bw.write("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a nibble to a hex character
|
||||
* @param nibble the nibble to convert.
|
||||
*/
|
||||
private static char toHex(int nibble) {
|
||||
return hexDigit[(nibble & 0xF)];
|
||||
}
|
||||
|
||||
/** A table of hex digits */
|
||||
private static final char[] hexDigit = {
|
||||
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
|
||||
};
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package build.tools.stripproperties;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Reads a properties file from standard input and writes an equivalent
|
||||
* properties file without comments to standard output.
|
||||
*/
|
||||
public class StripPropertiesCorba {
|
||||
|
||||
private static void error(String msg, Exception e) {
|
||||
System.err.println("ERROR: stripproperties: " + msg);
|
||||
if ( e != null ) {
|
||||
System.err.println("EXCEPTION: " + e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> infiles = new ArrayList<String>();
|
||||
private static List<String> outfiles = new ArrayList<String>();
|
||||
|
||||
private static boolean parseOptions(String args[]) {
|
||||
boolean ok = true;
|
||||
|
||||
for ( int i = 0; i < args.length ; i++ ) {
|
||||
if ( "-clean".equals(args[i]) && i+2 < args.length ) {
|
||||
infiles.add(args[++i]);
|
||||
outfiles.add(args[++i]);
|
||||
} else if ( args[i].charAt(0)=='@') {
|
||||
String filename = args[i].substring(1);
|
||||
FileInputStream finput = null;
|
||||
byte contents[] = null;
|
||||
try {
|
||||
finput = new FileInputStream(filename);
|
||||
int byteCount = finput.available();
|
||||
if ( byteCount <= 0 ) {
|
||||
error("The @file is empty", null);
|
||||
ok = false;
|
||||
} else {
|
||||
contents = new byte[byteCount];
|
||||
int bytesRead = finput.read(contents);
|
||||
if ( byteCount != bytesRead ) {
|
||||
error("Cannot read all of @file", null);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
} catch ( IOException e ) {
|
||||
error("cannot open " + filename, e);
|
||||
ok = false;
|
||||
}
|
||||
if ( finput != null ) {
|
||||
try {
|
||||
finput.close();
|
||||
} catch ( IOException e ) {
|
||||
ok = false;
|
||||
error("cannot close " + filename, e);
|
||||
}
|
||||
}
|
||||
if ( ok && contents != null ) {
|
||||
String tokens[] = (new String(contents)).split("\\s+");
|
||||
if ( tokens.length > 0 ) {
|
||||
ok = parseOptions(tokens);
|
||||
}
|
||||
}
|
||||
if ( !ok ) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
infiles.add(args[i]);
|
||||
outfiles.add(args[i]);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private static boolean stripFiles(List<String> infiles, List<String> outfiles) {
|
||||
boolean ok = true;
|
||||
Iterator<String> inIter = infiles.iterator();
|
||||
Iterator<String> outIter = outfiles.iterator();
|
||||
|
||||
for (; inIter.hasNext(); ) {
|
||||
String infile = inIter.next();
|
||||
String outfile = outIter.next();
|
||||
|
||||
Properties prop = new Properties();
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new BufferedInputStream(new FileInputStream(infile));
|
||||
prop.load(in);
|
||||
} catch ( FileNotFoundException e ) {
|
||||
error("Cannot access file " + infile, e);
|
||||
ok = false;
|
||||
} catch ( IOException e ) {
|
||||
error("IO exception processing file " + infile, e);
|
||||
ok = false;
|
||||
}
|
||||
if ( in != null ) {
|
||||
try {
|
||||
in.close();
|
||||
} catch ( IOException e ) {
|
||||
error("IO exception closing file " + infile, e);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if ( !ok ) {
|
||||
break;
|
||||
}
|
||||
|
||||
OutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(outfile);
|
||||
storeProperties(prop, out);
|
||||
out.flush();
|
||||
} catch ( IOException e ) {
|
||||
error("IO exception processing file " + outfile, e);
|
||||
ok = false;
|
||||
}
|
||||
if ( out != null ) {
|
||||
try {
|
||||
out.close();
|
||||
} catch ( IOException e ) {
|
||||
error("IO exception closing file " + outfile, e);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if ( !ok ) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip the properties filenames supplied, replacing their contents.
|
||||
* @param args Names of properties files to process and replace contents
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
boolean ok = parseOptions(args);
|
||||
if ( !ok || !stripFiles(infiles, outfiles) ) {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// --- code below here is adapted from java.util.Properties ---
|
||||
|
||||
private static final String specialSaveChars = "=: \t\r\n\f#!";
|
||||
|
||||
/*
|
||||
* Converts unicodes to encoded \uxxxx
|
||||
* and writes out any of the characters in specialSaveChars
|
||||
* with a preceding slash
|
||||
*/
|
||||
private static String saveConvert(String theString, boolean escapeSpace) {
|
||||
int len = theString.length();
|
||||
StringBuffer outBuffer = new StringBuffer(len*2);
|
||||
|
||||
for(int x=0; x<len; x++) {
|
||||
char aChar = theString.charAt(x);
|
||||
switch(aChar) {
|
||||
case ' ':
|
||||
if (x == 0 || escapeSpace) {
|
||||
outBuffer.append('\\');
|
||||
}
|
||||
outBuffer.append(' ');
|
||||
break;
|
||||
case '\\':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('\\');
|
||||
break;
|
||||
case '\t':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('t');
|
||||
break;
|
||||
case '\n':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('n');
|
||||
break;
|
||||
case '\r':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('r');
|
||||
break;
|
||||
case '\f':
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('f');
|
||||
break;
|
||||
default:
|
||||
if ((aChar < 0x0020) || (aChar == 0x007e) || (aChar > 0x00ff)) {
|
||||
outBuffer.append('\\');
|
||||
outBuffer.append('u');
|
||||
outBuffer.append(toHex((aChar >> 12) & 0xF));
|
||||
outBuffer.append(toHex((aChar >> 8) & 0xF));
|
||||
outBuffer.append(toHex((aChar >> 4) & 0xF));
|
||||
outBuffer.append(toHex( aChar & 0xF));
|
||||
} else {
|
||||
if (specialSaveChars.indexOf(aChar) != -1) {
|
||||
outBuffer.append('\\');
|
||||
}
|
||||
outBuffer.append(aChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outBuffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of <code>properties</code> to <code>out</code>.
|
||||
* The format is that of Properties.store with the following modifications:
|
||||
* <ul>
|
||||
* <li>No header or date is written
|
||||
* <li>Latin-1 characters are written as single bytes, not escape sequences
|
||||
* <li>Line breaks are indicated by a single \n independent of platform
|
||||
* <ul>
|
||||
*/
|
||||
private static void storeProperties(Properties properties, OutputStream out)
|
||||
throws IOException {
|
||||
BufferedWriter awriter;
|
||||
awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1"));
|
||||
for (Enumeration<Object> e = properties.keys(); e.hasMoreElements();) {
|
||||
String key = (String)e.nextElement();
|
||||
String val = (String)properties.get(key);
|
||||
key = saveConvert(key, true);
|
||||
|
||||
/* No need to escape embedded and trailing spaces for value, hence
|
||||
* pass false to flag.
|
||||
*/
|
||||
val = saveConvert(val, false);
|
||||
writeln(awriter, key + "=" + val);
|
||||
}
|
||||
awriter.flush();
|
||||
}
|
||||
|
||||
private static void writeln(BufferedWriter bw, String s) throws IOException {
|
||||
bw.write(s);
|
||||
bw.write("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a nibble to a hex character
|
||||
* @param nibble the nibble to convert.
|
||||
*/
|
||||
private static char toHex(int nibble) {
|
||||
return hexDigit[(nibble & 0xF)];
|
||||
}
|
||||
|
||||
/** A table of hex digits */
|
||||
private static final char[] hexDigit = {
|
||||
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
|
||||
};
|
||||
}
|
|
@ -34,7 +34,7 @@ PROGRAM = stripproperties
|
|||
include $(BUILDDIR)/common/Defs.gmk
|
||||
|
||||
BUILDTOOL_SOURCE_ROOT = $(BUILDDIR)/tools/src
|
||||
BUILDTOOL_MAIN = $(PKGDIR)/StripProperties.java
|
||||
BUILDTOOL_MAIN = $(PKGDIR)/StripPropertiesCorba.java
|
||||
|
||||
#
|
||||
# Build tool jar rules.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -423,6 +423,13 @@ public abstract class CDRInputStream
|
|||
impl.setByteBufferWithInfo(bbwi);
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if our ByteBuffer is sharing/equal to bb
|
||||
*/
|
||||
protected final boolean isSharing(ByteBuffer bb) {
|
||||
return (getByteBuffer() == bb);
|
||||
}
|
||||
|
||||
public final int getBufferLength() {
|
||||
return impl.getBufferLength();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -2412,7 +2412,6 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase
|
|||
|
||||
if (bbwi != null && getByteBuffer() != null)
|
||||
{
|
||||
int bbHash = System.identityHashCode(bbwi.byteBuffer);
|
||||
MessageMediator messageMediator = parent.getMessageMediator();
|
||||
if (messageMediator != null)
|
||||
{
|
||||
|
@ -2420,19 +2419,12 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase
|
|||
(CDROutputObject)messageMediator.getOutputObject();
|
||||
if (outputObj != null)
|
||||
{
|
||||
ByteBuffer outputBb = outputObj.getByteBuffer();
|
||||
|
||||
int oBbHash = 0;
|
||||
if (outputBb != null)
|
||||
if (outputObj.isSharing(getByteBuffer()))
|
||||
{
|
||||
oBbHash = System.identityHashCode(outputBb);
|
||||
if (bbHash == oBbHash) // shared?
|
||||
{
|
||||
// Set OutputStream's ByteBuffer and bbwi to null
|
||||
// so its ByteBuffer cannot be released to the pool
|
||||
outputObj.setByteBuffer(null);
|
||||
outputObj.setByteBufferWithInfo(null);
|
||||
}
|
||||
// Set OutputStream's ByteBuffer and bbwi to null
|
||||
// so its ByteBuffer cannot be released to the pool
|
||||
outputObj.setByteBuffer(null);
|
||||
outputObj.setByteBufferWithInfo(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -357,6 +357,13 @@ public abstract class CDROutputStream
|
|||
impl.setByteBuffer(byteBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if our ByteBuffer is sharing/equal to bb
|
||||
*/
|
||||
protected final boolean isSharing(ByteBuffer bb) {
|
||||
return (getByteBuffer() == bb);
|
||||
}
|
||||
|
||||
public final boolean isLittleEndian() {
|
||||
return impl.isLittleEndian();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -1902,7 +1902,6 @@ public class CDROutputStream_1_0 extends CDROutputStreamBase
|
|||
|
||||
if (getByteBufferWithInfo() != null && getByteBuffer() != null)
|
||||
{
|
||||
int bbHash = System.identityHashCode(bbwi.byteBuffer);
|
||||
MessageMediator messageMediator = parent.getMessageMediator();
|
||||
if (messageMediator != null)
|
||||
{
|
||||
|
@ -1910,19 +1909,12 @@ public class CDROutputStream_1_0 extends CDROutputStreamBase
|
|||
(CDRInputObject)messageMediator.getInputObject();
|
||||
if (inputObj != null)
|
||||
{
|
||||
ByteBuffer inputBb = inputObj.getByteBuffer();
|
||||
|
||||
int iBbHash = 0;
|
||||
if (inputBb != null)
|
||||
if (inputObj.isSharing(getByteBuffer()))
|
||||
{
|
||||
iBbHash = System.identityHashCode(inputBb);
|
||||
if (bbHash == iBbHash) // shared?
|
||||
{
|
||||
// Set InputStream's ByteBuffer and bbwi to null
|
||||
// so its ByteBuffer cannot be released to the pool
|
||||
inputObj.setByteBuffer(null);
|
||||
inputObj.setByteBufferWithInfo(null);
|
||||
}
|
||||
// Set InputStream's ByteBuffer and bbwi to null
|
||||
// so its ByteBuffer cannot be released to the pool
|
||||
inputObj.setByteBuffer(null);
|
||||
inputObj.setByteBufferWithInfo(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -113,6 +113,9 @@ import com.sun.corba.se.impl.protocol.giopmsgheaders.ReferenceAddr;
|
|||
import com.sun.corba.se.impl.transport.CorbaContactInfoListIteratorImpl;
|
||||
import com.sun.corba.se.impl.util.JDKBridge;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* ClientDelegate is the RMI client-side subcontract or representation
|
||||
* It implements RMI delegate as well as our internal ClientRequestDispatcher
|
||||
|
@ -122,6 +125,9 @@ public class CorbaClientRequestDispatcherImpl
|
|||
implements
|
||||
ClientRequestDispatcher
|
||||
{
|
||||
private ConcurrentMap<ContactInfo, Object> locks =
|
||||
new ConcurrentHashMap<ContactInfo, Object>();
|
||||
|
||||
public OutputObject beginRequest(Object self, String opName,
|
||||
boolean isOneWay, ContactInfo contactInfo)
|
||||
{
|
||||
|
@ -148,8 +154,21 @@ public class CorbaClientRequestDispatcherImpl
|
|||
|
||||
// This locking is done so that multiple connections are not created
|
||||
// for the same endpoint
|
||||
//6929137 - Synchronized on contactInfo to avoid blocking across multiple endpoints
|
||||
synchronized (contactInfo) {
|
||||
// 7046238 - Synchronization on a single monitor for contactInfo parameters
|
||||
// with identical hashCode(), so we lock on same monitor for equal parameters
|
||||
// (which can refer to equal (in terms of equals()) but not the same objects)
|
||||
|
||||
Object lock = locks.get(contactInfo);
|
||||
|
||||
if (lock == null) {
|
||||
Object newLock = new Object();
|
||||
lock = locks.putIfAbsent(contactInfo, newLock);
|
||||
if (lock == null) {
|
||||
lock = newLock;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
if (contactInfo.isConnectionBased()) {
|
||||
if (contactInfo.shouldCacheConnection()) {
|
||||
connection = (CorbaConnection)
|
||||
|
@ -254,7 +273,7 @@ public class CorbaClientRequestDispatcherImpl
|
|||
registerWaiter(messageMediator);
|
||||
|
||||
// Do connection reclaim now
|
||||
synchronized (contactInfo) {
|
||||
synchronized (lock) {
|
||||
if (contactInfo.isConnectionBased()) {
|
||||
if (contactInfo.shouldCacheConnection()) {
|
||||
OutboundConnectionCache connectionCache =
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
^src/share/tools/IdealGraphVisualizer/build/
|
||||
^src/share/tools/IdealGraphVisualizer/dist/
|
||||
^.hgtip
|
||||
.DS_Store
|
||||
|
|
|
@ -172,3 +172,67 @@ d283b82966712b353fa307845a1316da42a355f4 hs21-b10
|
|||
3aea9e9feb073f5500e031be6186666bcae89aa2 hs21-b11
|
||||
9ad1548c6b63d596c411afc35147ffd5254426d9 jdk7-b142
|
||||
9ad1548c6b63d596c411afc35147ffd5254426d9 hs21-b12
|
||||
c149193c768b8b7233da4c3a3fdc0756b975848e hs21-b13
|
||||
c149193c768b8b7233da4c3a3fdc0756b975848e jdk7-b143
|
||||
0cc8a70952c368e06de2adab1f2649a408f5e577 jdk8-b01
|
||||
31e253c1da429124bb87570ab095d9bc89850d0a jdk8-b02
|
||||
3a2fb61165dfc72e398179a2796d740c8da5b8c0 jdk8-b03
|
||||
0fa3ace511fe98fe948e751531f3e2b7c60c8376 jdk8-b04
|
||||
dce7d24674f4d0bed00de24f00119057fdce7cfb jdk8-b05
|
||||
0db80d8e77fccddf5e6fa49963226b54ac7d0f62 jdk8-b06
|
||||
3f0cf875af83f55ec5e1a5cea80455315f9322a2 jdk8-b07
|
||||
0cc8a70952c368e06de2adab1f2649a408f5e577 hs22-b01
|
||||
7c29742c41b44fb0cd5a13c7ac8834f3f2ca649e hs22-b02
|
||||
3a2fb61165dfc72e398179a2796d740c8da5b8c0 hs22-b03
|
||||
ce9bde819dcba4a5d2822229d9183e69c74326ca hs22-b04
|
||||
513a84dd0f8b56dc0836b4e0bdd5dd0a778fc634 hs22-b05
|
||||
650d15d8f37255d3b805aa00c5bd1c30984b203d hs22-b06
|
||||
da883b9e6d3788057f9577e72712998ed82c9b7e hs23-b01
|
||||
49ed7eacfd16616166ff066493143889741097af jdk8-b08
|
||||
7c20d272643f47195478708eff593a9cce40fec4 jdk8-b09
|
||||
e4f412d2b75d2c797acff965aa2c420e3d358f09 hs23-b02
|
||||
d815de2e85e511b7deab2a83cf80c0224d011da9 jdk8-b10
|
||||
4d3850d9d326ac3a9bee2d867727e954322d014e hs23-b03
|
||||
4538caeef7b6cbd4302bebced805d65e68ccf301 jdk8-b11
|
||||
6534482ff68ad79066dfe15dfb6d8905f09681bd hs23-b04
|
||||
1d3900713a67a0a39faf4e12c9c158d55aebef87 jdk8-b12
|
||||
3e609627e780736f372eb14d29bb9b5e53b21fbf hs23-b05
|
||||
b92ca8e229d29004f840c67e620833d23a346761 jdk8-b13
|
||||
088d09a130ff02d8f5f05e92256baabe412f0439 jdk8-b14
|
||||
6c2a55d4902f202e1c2de1df17b7da083a2c31e8 hs23-b06
|
||||
fde2a39ed7f39233b287fbc278f437aac06c275b jdk8-b15
|
||||
d1f29d4e0bc60e8bd7ae961f1306d8ab33290212 jdk8-b17
|
||||
d1f29d4e0bc60e8bd7ae961f1306d8ab33290212 jdk8-b16
|
||||
6de8c9ba5907e4c5ca05ac4b8d84a8e2cbd92399 hs23-b07
|
||||
a2fef924d8e6f37dac2a887315e3502876cc8e24 hs23-b08
|
||||
61165f53f1656b9f99e4fb806429bf98b99d59c3 jdk8-b18
|
||||
4bcf61041217f8677dcec18e90e9196acc945bba hs23-b09
|
||||
9232e0ecbc2cec54dcc8f93004fb00c214446460 jdk8-b19
|
||||
fe2c8764998112b7fefcd7d41599714813ae4327 jdk8-b20
|
||||
9952d1c439d64c5fd4ad1236a63a62bd5a49d4c3 jdk8-b21
|
||||
513351373923f74a7c91755748b95c9771e59f96 hs23-b10
|
||||
24727fb37561779077fdfa5a33342246f20e5c0f jdk8-b22
|
||||
dcc292399a39113957eebbd3e487b7e05e2c79fc hs23-b11
|
||||
e850d8e7ea54b91c7aa656e297f0f9f38dd4c296 jdk8-b23
|
||||
9e177d44b10fe92ecffa965fef9c5ac5433c1b46 hs23-b12
|
||||
a80fd4f45d7aaa154ed2f86a129f3c9c4035ec7a jdk8-b24
|
||||
b22de824749922986ce4d442bed029916b832807 hs23-b13
|
||||
64b46f975ab82948c1e021e17775ff4fab8bc40e hs23-b14
|
||||
9ad8feb5afbddec46d3cfe29fb5f73c2e99d5a43 jdk8-b25
|
||||
d71e662fe03741b6de498ca2077220148405a978 hs23-b15
|
||||
fd3060701216a11c0df6dcd053c6fd7c2b17a42c jdk8-b26
|
||||
f92a171cf0071ca6c3fa8231d7d570377f8b2f4d hs23-b16
|
||||
f92a171cf0071ca6c3fa8231d7d570377f8b2f4d hs23-b16
|
||||
931e5f39e365a0d550d79148ff87a7f9e864d2e1 hs23-b16
|
||||
3b24e7e01d20ca590d0f86b1222bb7c3f1a2aa2d jdk8-b27
|
||||
975c4105f1e2ef1190a75b77124033f1fd4290b5 hs24-b01
|
||||
b183b0863611b85dbac16f3b08b40ba978756d19 jdk8-b28
|
||||
030b5306d60f140e822e4a6d301744cb110ff0c8 hs24-b02
|
||||
b45b5c564098c58ea69e7cff3f7d341f0254dd1d jdk8-b29
|
||||
d61761bf305031c94f7f8eca49abd978b7d3c5da jdk8-b30
|
||||
dfae0140457cfb2c381d7679735fbedbae862c62 hs24-b03
|
||||
f4767e53d6e0d5da7e3f1775904076cce54247c1 hs24-b04
|
||||
0cd147eaa673d1642b2f466f5dc257cf192db524 jdk8-b31
|
||||
27863e4586de38be7dd17da4163f542038f4d1d7 hs24-b05
|
||||
25410a347ebb0bef166c4338a90d9dea82463a20 jdk8-b32
|
||||
cd47da9383cd932cb2b659064057feafa2a91134 hs24-b06
|
||||
|
|
|
@ -1 +1 @@
|
|||
project=jdk7
|
||||
project=jdk8
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -48,17 +48,18 @@ sun.jvm.hotspot.asm.x86 \
|
|||
sun.jvm.hotspot.bugspot \
|
||||
sun.jvm.hotspot.bugspot.tree \
|
||||
sun.jvm.hotspot.c1 \
|
||||
sun.jvm.hotspot.ci \
|
||||
sun.jvm.hotspot.code \
|
||||
sun.jvm.hotspot.compiler \
|
||||
sun.jvm.hotspot.debugger \
|
||||
sun.jvm.hotspot.debugger.amd64 \
|
||||
sun.jvm.hotspot.debugger.bsd \
|
||||
sun.jvm.hotspot.debugger.bsd.amd64 \
|
||||
sun.jvm.hotspot.debugger.bsd.x86 \
|
||||
sun.jvm.hotspot.debugger.cdbg \
|
||||
sun.jvm.hotspot.debugger.cdbg.basic \
|
||||
sun.jvm.hotspot.debugger.cdbg.basic.amd64 \
|
||||
sun.jvm.hotspot.debugger.cdbg.basic.x86 \
|
||||
sun.jvm.hotspot.debugger.dbx \
|
||||
sun.jvm.hotspot.debugger.dbx.sparc \
|
||||
sun.jvm.hotspot.debugger.dbx.x86 \
|
||||
sun.jvm.hotspot.debugger.dummy \
|
||||
sun.jvm.hotspot.debugger.ia64 \
|
||||
sun.jvm.hotspot.debugger.linux \
|
||||
|
@ -76,7 +77,6 @@ sun.jvm.hotspot.debugger.remote.amd64 \
|
|||
sun.jvm.hotspot.debugger.remote.sparc \
|
||||
sun.jvm.hotspot.debugger.remote.x86 \
|
||||
sun.jvm.hotspot.debugger.sparc \
|
||||
sun.jvm.hotspot.debugger.win32 \
|
||||
sun.jvm.hotspot.debugger.win32.coff \
|
||||
sun.jvm.hotspot.debugger.windbg \
|
||||
sun.jvm.hotspot.debugger.windbg.amd64 \
|
||||
|
@ -84,6 +84,7 @@ sun.jvm.hotspot.debugger.windbg.ia64 \
|
|||
sun.jvm.hotspot.debugger.windbg.x86 \
|
||||
sun.jvm.hotspot.debugger.x86 \
|
||||
sun.jvm.hotspot.gc_implementation \
|
||||
sun.jvm.hotspot.gc_implementation.g1 \
|
||||
sun.jvm.hotspot.gc_implementation.parallelScavenge \
|
||||
sun.jvm.hotspot.gc_implementation.shared \
|
||||
sun.jvm.hotspot.gc_interface \
|
||||
|
@ -91,9 +92,14 @@ sun.jvm.hotspot.interpreter \
|
|||
sun.jvm.hotspot.jdi \
|
||||
sun.jvm.hotspot.livejvm \
|
||||
sun.jvm.hotspot.memory \
|
||||
sun.jvm.hotspot.opto \
|
||||
sun.jvm.hotspot.oops \
|
||||
sun.jvm.hotspot.prims \
|
||||
sun.jvm.hotspot.runtime \
|
||||
sun.jvm.hotspot.runtime.amd64 \
|
||||
sun.jvm.hotspot.runtime.bsd \
|
||||
sun.jvm.hotspot.runtime.bsd_amd64 \
|
||||
sun.jvm.hotspot.runtime.bsd_x86 \
|
||||
sun.jvm.hotspot.runtime.ia64 \
|
||||
sun.jvm.hotspot.runtime.linux \
|
||||
sun.jvm.hotspot.runtime.linux_amd64 \
|
||||
|
@ -139,17 +145,18 @@ sun/jvm/hotspot/asm/x86/*.java \
|
|||
sun/jvm/hotspot/bugspot/*.java \
|
||||
sun/jvm/hotspot/bugspot/tree/*.java \
|
||||
sun/jvm/hotspot/c1/*.java \
|
||||
sun/jvm/hotspot/ci/*.java \
|
||||
sun/jvm/hotspot/code/*.java \
|
||||
sun/jvm/hotspot/compiler/*.java \
|
||||
sun/jvm/hotspot/debugger/*.java \
|
||||
sun/jvm/hotspot/debugger/amd64/*.java \
|
||||
sun/jvm/hotspot/debugger/bsd/*.java \
|
||||
sun/jvm/hotspot/debugger/bsd/amd64/*.java \
|
||||
sun/jvm/hotspot/debugger/bsd/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/basic/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/dbx/*.java \
|
||||
sun/jvm/hotspot/debugger/dbx/sparc/*.java \
|
||||
sun/jvm/hotspot/debugger/dbx/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/dummy/*.java \
|
||||
sun/jvm/hotspot/debugger/ia64/*.java \
|
||||
sun/jvm/hotspot/debugger/linux/*.java \
|
||||
|
@ -165,19 +172,26 @@ sun/jvm/hotspot/debugger/remote/amd64/*.java \
|
|||
sun/jvm/hotspot/debugger/remote/sparc/*.java \
|
||||
sun/jvm/hotspot/debugger/remote/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/sparc/*.java \
|
||||
sun/jvm/hotspot/debugger/win32/*.java \
|
||||
sun/jvm/hotspot/debugger/win32/coff/*.java \
|
||||
sun/jvm/hotspot/debugger/windbg/*.java \
|
||||
sun/jvm/hotspot/debugger/windbg/ia64/*.java \
|
||||
sun/jvm/hotspot/debugger/windbg/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/x86/*.java \
|
||||
sun/jvm/hotspot/gc_implementation/g1/*.java \
|
||||
sun/jvm/hotspot/gc_implementation/parallelScavenge/*.java \
|
||||
sun/jvm/hotspot/gc_implementation/shared/*.java \
|
||||
sun/jvm/hotspot/interpreter/*.java \
|
||||
sun/jvm/hotspot/jdi/*.java \
|
||||
sun/jvm/hotspot/livejvm/*.java \
|
||||
sun/jvm/hotspot/memory/*.java \
|
||||
sun/jvm/hotspot/oops/*.java \
|
||||
sun/jvm/hotspot/opto/*.java \
|
||||
sun/jvm/hotspot/prims/*.java \
|
||||
sun/jvm/hotspot/runtime/*.java \
|
||||
sun/jvm/hotspot/runtime/amd64/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd_amd64/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd_x86/*.java \
|
||||
sun/jvm/hotspot/runtime/ia64/*.java \
|
||||
sun/jvm/hotspot/runtime/linux/*.java \
|
||||
sun/jvm/hotspot/runtime/linux_amd64/*.java \
|
||||
|
|
|
@ -70,6 +70,14 @@ fi
|
|||
|
||||
SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/js.jar
|
||||
|
||||
if [ ! -z "$SA_TYPEDB" ]; then
|
||||
if [ ! -f $SA_TYPEDB ]; then
|
||||
echo "$SA_TYPEDB is unreadable"
|
||||
exit 1
|
||||
fi
|
||||
OPTIONS="-Dsun.jvm.hotspot.typedb=$SA_TYPEDB ${OPTIONS}"
|
||||
fi
|
||||
|
||||
OPTIONS="-Djava.system.class.loader=sun.jvm.hotspot.SALauncherLoader ${OPTIONS}"
|
||||
|
||||
SA_JAVA_CMD="$SA_PREFIX_CMD $SA_JAVA -showversion ${OPTIONS} -cp $SA_CLASSPATH $SA_OPTIONS"
|
||||
|
|
|
@ -67,6 +67,14 @@ fi
|
|||
|
||||
SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar::$STARTDIR/lib/js.jar
|
||||
|
||||
if [ ! -z "$SA_TYPEDB" ]; then
|
||||
if [ ! -f $SA_TYPEDB ]; then
|
||||
echo "$SA_TYPEDB is unreadable"
|
||||
exit 1
|
||||
fi
|
||||
OPTIONS="-Dsun.jvm.hotspot.typedb=$SA_TYPEDB ${OPTIONS}"
|
||||
fi
|
||||
|
||||
OPTIONS="-Djava.system.class.loader=sun.jvm.hotspot.SALauncherLoader ${OPTIONS}"
|
||||
|
||||
SA_JAVA_CMD="$SA_PREFIX_CMD $SA_JAVA -d64 -showversion ${OPTIONS} -cp $SA_CLASSPATH $SA_OPTIONS"
|
||||
|
|
413
hotspot/agent/src/os/bsd/BsdDebuggerLocal.c
Normal file
413
hotspot/agent/src/os/bsd/BsdDebuggerLocal.c
Normal file
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <jni.h>
|
||||
#include "libproc.h"
|
||||
|
||||
#if defined(x86_64) && !defined(amd64)
|
||||
#define amd64 1
|
||||
#endif
|
||||
|
||||
#ifdef i386
|
||||
#include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h"
|
||||
#endif
|
||||
|
||||
#ifdef amd64
|
||||
#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
|
||||
#endif
|
||||
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
#include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h"
|
||||
#endif
|
||||
|
||||
static jfieldID p_ps_prochandle_ID = 0;
|
||||
static jfieldID threadList_ID = 0;
|
||||
static jfieldID loadObjectList_ID = 0;
|
||||
|
||||
static jmethodID createClosestSymbol_ID = 0;
|
||||
static jmethodID createLoadObject_ID = 0;
|
||||
static jmethodID getThreadForThreadId_ID = 0;
|
||||
static jmethodID listAdd_ID = 0;
|
||||
|
||||
#define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }
|
||||
#define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}
|
||||
|
||||
static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
|
||||
}
|
||||
|
||||
static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {
|
||||
jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID);
|
||||
return (struct ps_prochandle*)(intptr_t)ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: init0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0
|
||||
(JNIEnv *env, jclass cls) {
|
||||
jclass listClass;
|
||||
|
||||
if (init_libproc(getenv("LIBSAPROC_DEBUG") != NULL) != true) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("can't initialize libproc");
|
||||
}
|
||||
|
||||
// fields we use
|
||||
p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J");
|
||||
CHECK_EXCEPTION;
|
||||
threadList_ID = (*env)->GetFieldID(env, cls, "threadList", "Ljava/util/List;");
|
||||
CHECK_EXCEPTION;
|
||||
loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;");
|
||||
CHECK_EXCEPTION;
|
||||
|
||||
// methods we use
|
||||
createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol",
|
||||
"(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
|
||||
CHECK_EXCEPTION;
|
||||
createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject",
|
||||
"(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");
|
||||
CHECK_EXCEPTION;
|
||||
getThreadForThreadId_ID = (*env)->GetMethodID(env, cls, "getThreadForThreadId",
|
||||
"(J)Lsun/jvm/hotspot/debugger/ThreadProxy;");
|
||||
CHECK_EXCEPTION;
|
||||
// java.util.List method we call
|
||||
listClass = (*env)->FindClass(env, "java/util/List");
|
||||
CHECK_EXCEPTION;
|
||||
listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z");
|
||||
CHECK_EXCEPTION;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
#ifdef _LP64
|
||||
return 8;
|
||||
#else
|
||||
return 4;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void fillThreadsAndLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
|
||||
int n = 0, i = 0;
|
||||
|
||||
// add threads
|
||||
n = get_num_threads(ph);
|
||||
for (i = 0; i < n; i++) {
|
||||
jobject thread;
|
||||
jobject threadList;
|
||||
lwpid_t lwpid;
|
||||
|
||||
lwpid = get_lwp_id(ph, i);
|
||||
thread = (*env)->CallObjectMethod(env, this_obj, getThreadForThreadId_ID,
|
||||
(jlong)lwpid);
|
||||
CHECK_EXCEPTION;
|
||||
threadList = (*env)->GetObjectField(env, this_obj, threadList_ID);
|
||||
CHECK_EXCEPTION;
|
||||
(*env)->CallBooleanMethod(env, threadList, listAdd_ID, thread);
|
||||
CHECK_EXCEPTION;
|
||||
}
|
||||
|
||||
// add load objects
|
||||
n = get_num_libs(ph);
|
||||
for (i = 0; i < n; i++) {
|
||||
uintptr_t base;
|
||||
const char* name;
|
||||
jobject loadObject;
|
||||
jobject loadObjectList;
|
||||
|
||||
base = get_lib_base(ph, i);
|
||||
name = get_lib_name(ph, i);
|
||||
loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,
|
||||
(*env)->NewStringUTF(env, name), (jlong)0, (jlong)base);
|
||||
CHECK_EXCEPTION;
|
||||
loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);
|
||||
CHECK_EXCEPTION;
|
||||
(*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject);
|
||||
CHECK_EXCEPTION;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I
|
||||
(JNIEnv *env, jobject this_obj, jint jpid) {
|
||||
|
||||
struct ps_prochandle* ph;
|
||||
if ( (ph = Pgrab(jpid)) == NULL) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
|
||||
}
|
||||
(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
|
||||
fillThreadsAndLoadObjects(env, this_obj, ph);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
|
||||
(JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) {
|
||||
const char *execName_cstr;
|
||||
const char *coreName_cstr;
|
||||
jboolean isCopy;
|
||||
struct ps_prochandle* ph;
|
||||
|
||||
execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy);
|
||||
CHECK_EXCEPTION;
|
||||
coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);
|
||||
CHECK_EXCEPTION;
|
||||
|
||||
if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {
|
||||
(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
|
||||
(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");
|
||||
}
|
||||
(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
|
||||
(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
|
||||
(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
|
||||
fillThreadsAndLoadObjects(env, this_obj, ph);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: detach0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||
if (ph != NULL) {
|
||||
Prelease(ph);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByName0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0
|
||||
(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
|
||||
const char *objectName_cstr, *symbolName_cstr;
|
||||
jlong addr;
|
||||
jboolean isCopy;
|
||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||
|
||||
objectName_cstr = NULL;
|
||||
if (objectName != NULL) {
|
||||
objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy);
|
||||
CHECK_EXCEPTION_(0);
|
||||
}
|
||||
symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);
|
||||
CHECK_EXCEPTION_(0);
|
||||
|
||||
addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);
|
||||
|
||||
if (objectName_cstr != NULL) {
|
||||
(*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByAddress0
|
||||
* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
|
||||
(JNIEnv *env, jobject this_obj, jlong addr) {
|
||||
uintptr_t offset;
|
||||
const char* sym = NULL;
|
||||
|
||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||
sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
|
||||
if (sym == NULL) return 0;
|
||||
return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
|
||||
(*env)->NewStringUTF(env, sym), (jlong)offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: readBytesFromProcess0
|
||||
* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0
|
||||
(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {
|
||||
|
||||
jboolean isCopy;
|
||||
jbyteArray array;
|
||||
jbyte *bufPtr;
|
||||
ps_err_e err;
|
||||
|
||||
array = (*env)->NewByteArray(env, numBytes);
|
||||
CHECK_EXCEPTION_(0);
|
||||
bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);
|
||||
CHECK_EXCEPTION_(0);
|
||||
|
||||
err = ps_pread(get_proc_handle(env, this_obj), (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);
|
||||
(*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);
|
||||
return (err == PS_OK)? array : 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
|
||||
(JNIEnv *env, jobject this_obj, jint lwp_id) {
|
||||
|
||||
struct reg gregs;
|
||||
jboolean isCopy;
|
||||
jlongArray array;
|
||||
jlong *regs;
|
||||
|
||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||
if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);
|
||||
}
|
||||
|
||||
#undef NPRGREG
|
||||
#ifdef i386
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG
|
||||
#endif
|
||||
#ifdef ia64
|
||||
#define NPRGREG IA64_REG_COUNT
|
||||
#endif
|
||||
#ifdef amd64
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
|
||||
#endif
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG
|
||||
#endif
|
||||
|
||||
array = (*env)->NewLongArray(env, NPRGREG);
|
||||
CHECK_EXCEPTION_(0);
|
||||
regs = (*env)->GetLongArrayElements(env, array, &isCopy);
|
||||
|
||||
#undef REG_INDEX
|
||||
|
||||
#ifdef i386
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##reg
|
||||
|
||||
regs[REG_INDEX(GS)] = (uintptr_t) gregs.r_gs;
|
||||
regs[REG_INDEX(FS)] = (uintptr_t) gregs.r_fs;
|
||||
regs[REG_INDEX(ES)] = (uintptr_t) gregs.r_es;
|
||||
regs[REG_INDEX(DS)] = (uintptr_t) gregs.r_ds;
|
||||
regs[REG_INDEX(EDI)] = (uintptr_t) gregs.r_edi;
|
||||
regs[REG_INDEX(ESI)] = (uintptr_t) gregs.r_esi;
|
||||
regs[REG_INDEX(FP)] = (uintptr_t) gregs.r_ebp;
|
||||
regs[REG_INDEX(SP)] = (uintptr_t) gregs.r_isp;
|
||||
regs[REG_INDEX(EBX)] = (uintptr_t) gregs.r_ebx;
|
||||
regs[REG_INDEX(EDX)] = (uintptr_t) gregs.r_edx;
|
||||
regs[REG_INDEX(ECX)] = (uintptr_t) gregs.r_ecx;
|
||||
regs[REG_INDEX(EAX)] = (uintptr_t) gregs.r_eax;
|
||||
regs[REG_INDEX(PC)] = (uintptr_t) gregs.r_eip;
|
||||
regs[REG_INDEX(CS)] = (uintptr_t) gregs.r_cs;
|
||||
regs[REG_INDEX(SS)] = (uintptr_t) gregs.r_ss;
|
||||
|
||||
#endif /* i386 */
|
||||
|
||||
#if ia64
|
||||
regs = (*env)->GetLongArrayElements(env, array, &isCopy);
|
||||
int i;
|
||||
for (i = 0; i < NPRGREG; i++ ) {
|
||||
regs[i] = 0xDEADDEAD;
|
||||
}
|
||||
#endif /* ia64 */
|
||||
|
||||
#ifdef amd64
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
|
||||
|
||||
regs[REG_INDEX(R15)] = gregs.r_r15;
|
||||
regs[REG_INDEX(R14)] = gregs.r_r14;
|
||||
regs[REG_INDEX(R13)] = gregs.r_r13;
|
||||
regs[REG_INDEX(R12)] = gregs.r_r12;
|
||||
regs[REG_INDEX(RBP)] = gregs.r_rbp;
|
||||
regs[REG_INDEX(RBX)] = gregs.r_rbx;
|
||||
regs[REG_INDEX(R11)] = gregs.r_r11;
|
||||
regs[REG_INDEX(R10)] = gregs.r_r10;
|
||||
regs[REG_INDEX(R9)] = gregs.r_r9;
|
||||
regs[REG_INDEX(R8)] = gregs.r_r8;
|
||||
regs[REG_INDEX(RAX)] = gregs.r_rax;
|
||||
regs[REG_INDEX(RCX)] = gregs.r_rcx;
|
||||
regs[REG_INDEX(RDX)] = gregs.r_rdx;
|
||||
regs[REG_INDEX(RSI)] = gregs.r_rsi;
|
||||
regs[REG_INDEX(RDI)] = gregs.r_rdi;
|
||||
regs[REG_INDEX(RIP)] = gregs.r_rip;
|
||||
regs[REG_INDEX(CS)] = gregs.r_cs;
|
||||
regs[REG_INDEX(RSP)] = gregs.r_rsp;
|
||||
regs[REG_INDEX(SS)] = gregs.r_ss;
|
||||
// regs[REG_INDEX(FSBASE)] = gregs.fs_base;
|
||||
// regs[REG_INDEX(GSBASE)] = gregs.gs_base;
|
||||
// regs[REG_INDEX(DS)] = gregs.ds;
|
||||
// regs[REG_INDEX(ES)] = gregs.es;
|
||||
// regs[REG_INDEX(FS)] = gregs.fs;
|
||||
// regs[REG_INDEX(GS)] = gregs.gs;
|
||||
|
||||
#endif /* amd64 */
|
||||
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_##reg
|
||||
|
||||
#ifdef _LP64
|
||||
regs[REG_INDEX(R_PSR)] = gregs.tstate;
|
||||
regs[REG_INDEX(R_PC)] = gregs.tpc;
|
||||
regs[REG_INDEX(R_nPC)] = gregs.tnpc;
|
||||
regs[REG_INDEX(R_Y)] = gregs.y;
|
||||
#else
|
||||
regs[REG_INDEX(R_PSR)] = gregs.psr;
|
||||
regs[REG_INDEX(R_PC)] = gregs.pc;
|
||||
regs[REG_INDEX(R_nPC)] = gregs.npc;
|
||||
regs[REG_INDEX(R_Y)] = gregs.y;
|
||||
#endif
|
||||
regs[REG_INDEX(R_G0)] = 0 ;
|
||||
regs[REG_INDEX(R_G1)] = gregs.u_regs[0];
|
||||
regs[REG_INDEX(R_G2)] = gregs.u_regs[1];
|
||||
regs[REG_INDEX(R_G3)] = gregs.u_regs[2];
|
||||
regs[REG_INDEX(R_G4)] = gregs.u_regs[3];
|
||||
regs[REG_INDEX(R_G5)] = gregs.u_regs[4];
|
||||
regs[REG_INDEX(R_G6)] = gregs.u_regs[5];
|
||||
regs[REG_INDEX(R_G7)] = gregs.u_regs[6];
|
||||
regs[REG_INDEX(R_O0)] = gregs.u_regs[7];
|
||||
regs[REG_INDEX(R_O1)] = gregs.u_regs[8];
|
||||
regs[REG_INDEX(R_O2)] = gregs.u_regs[ 9];
|
||||
regs[REG_INDEX(R_O3)] = gregs.u_regs[10];
|
||||
regs[REG_INDEX(R_O4)] = gregs.u_regs[11];
|
||||
regs[REG_INDEX(R_O5)] = gregs.u_regs[12];
|
||||
regs[REG_INDEX(R_O6)] = gregs.u_regs[13];
|
||||
regs[REG_INDEX(R_O7)] = gregs.u_regs[14];
|
||||
#endif /* sparc */
|
||||
|
||||
|
||||
(*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);
|
||||
return array;
|
||||
}
|
406
hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m
Normal file
406
hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m
Normal file
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <objc/objc-runtime.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
#include <JavaVM/jni.h>
|
||||
|
||||
#import <mach/mach.h>
|
||||
#import <mach/mach_types.h>
|
||||
#import <sys/sysctl.h>
|
||||
#import <stdlib.h>
|
||||
|
||||
jboolean debug = JNI_FALSE;
|
||||
|
||||
static jfieldID symbolicatorID = 0; // set in _init0
|
||||
static jfieldID taskID = 0; // set in _init0
|
||||
|
||||
static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {
|
||||
(*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);
|
||||
}
|
||||
|
||||
static id getSymbolicator(JNIEnv *env, jobject this_obj) {
|
||||
jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);
|
||||
return (id)(intptr_t)ptr;
|
||||
}
|
||||
|
||||
static void putTask(JNIEnv *env, jobject this_obj, task_t task) {
|
||||
(*env)->SetLongField(env, this_obj, taskID, (jlong)task);
|
||||
}
|
||||
|
||||
static task_t getTask(JNIEnv *env, jobject this_obj) {
|
||||
jlong ptr = (*env)->GetLongField(env, this_obj, taskID);
|
||||
return (task_t)ptr;
|
||||
}
|
||||
|
||||
#define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }
|
||||
#define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}
|
||||
|
||||
static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
#define hsdb_thread_state_t x86_thread_state32_t
|
||||
#define hsdb_float_state_t x86_float_state32_t
|
||||
#define HSDB_THREAD_STATE x86_THREAD_STATE32
|
||||
#define HSDB_FLOAT_STATE x86_FLOAT_STATE32
|
||||
#define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
|
||||
#define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE32_COUNT
|
||||
#elif defined(__x86_64__)
|
||||
#define hsdb_thread_state_t x86_thread_state64_t
|
||||
#define hsdb_float_state_t x86_float_state64_t
|
||||
#define HSDB_THREAD_STATE x86_THREAD_STATE64
|
||||
#define HSDB_FLOAT_STATE x86_FLOAT_STATE64
|
||||
#define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
|
||||
#define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT
|
||||
#else
|
||||
#error "Unsupported architecture"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: init0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {
|
||||
symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");
|
||||
taskID = (*env)->GetFieldID(env, cls, "task", "J");
|
||||
CHECK_EXCEPTION;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByName0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
|
||||
jlong address = 0;
|
||||
|
||||
JNF_COCOA_ENTER(env);
|
||||
NSString *symbolNameString = JNFJavaToNSString(env, symbolName);
|
||||
|
||||
if (debug) {
|
||||
printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
|
||||
}
|
||||
|
||||
id symbolicator = getSymbolicator(env, this_obj);
|
||||
if (symbolicator != nil) {
|
||||
uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;
|
||||
address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
|
||||
}
|
||||
JNF_COCOA_EXIT(env);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: readBytesFromProcess0
|
||||
* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {
|
||||
if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
|
||||
|
||||
// must allocate storage instead of using former parameter buf
|
||||
jboolean isCopy;
|
||||
jbyteArray array;
|
||||
jbyte *bufPtr;
|
||||
|
||||
array = (*env)->NewByteArray(env, numBytes);
|
||||
CHECK_EXCEPTION_(0);
|
||||
|
||||
unsigned long alignedAddress;
|
||||
unsigned long alignedLength;
|
||||
kern_return_t result;
|
||||
vm_offset_t *pages;
|
||||
int *mapped;
|
||||
long pageCount;
|
||||
uint byteCount;
|
||||
int i;
|
||||
unsigned long remaining;
|
||||
|
||||
alignedAddress = trunc_page(addr);
|
||||
if (addr != alignedAddress) {
|
||||
alignedLength += addr - alignedAddress;
|
||||
}
|
||||
alignedLength = round_page(numBytes);
|
||||
pageCount = alignedLength/vm_page_size;
|
||||
|
||||
// Allocate storage for pages and flags.
|
||||
pages = malloc(pageCount * sizeof(vm_offset_t));
|
||||
mapped = calloc(pageCount, sizeof(int));
|
||||
|
||||
task_t gTask = getTask(env, this_obj);
|
||||
// Try to read each of the pages.
|
||||
for (i = 0; i < pageCount; i++) {
|
||||
result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size,
|
||||
&pages[i], &byteCount);
|
||||
mapped[i] = (result == KERN_SUCCESS);
|
||||
// assume all failures are unmapped pages
|
||||
}
|
||||
|
||||
if (debug) fprintf(stderr, "%ld pages\n", pageCount);
|
||||
|
||||
remaining = numBytes;
|
||||
|
||||
for (i = 0; i < pageCount; i++) {
|
||||
unsigned long len = vm_page_size;
|
||||
unsigned long start = 0;
|
||||
|
||||
if (i == 0) {
|
||||
start = addr - alignedAddress;
|
||||
len = vm_page_size - start;
|
||||
}
|
||||
|
||||
if (i == (pageCount - 1)) {
|
||||
len = remaining;
|
||||
}
|
||||
|
||||
if (mapped[i]) {
|
||||
if (debug) fprintf(stderr, "page %d mapped (len %ld start %ld)\n", i, len, start);
|
||||
(*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start));
|
||||
vm_deallocate(mach_task_self(), pages[i], vm_page_size);
|
||||
}
|
||||
|
||||
remaining -= len;
|
||||
}
|
||||
|
||||
free (pages);
|
||||
free (mapped);
|
||||
return array;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal
|
||||
* Method: getThreadIntegerRegisterSet0
|
||||
* Signature: (I)[J
|
||||
*/
|
||||
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(JNIEnv *env, jobject this_obj, jint lwp_id) {
|
||||
if (debug)
|
||||
printf("getThreadRegisterSet0 called\n");
|
||||
|
||||
kern_return_t result;
|
||||
thread_t tid;
|
||||
mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT;
|
||||
hsdb_thread_state_t state;
|
||||
unsigned int *r;
|
||||
int i;
|
||||
jlongArray registerArray;
|
||||
jlong *primitiveArray;
|
||||
|
||||
tid = lwp_id;
|
||||
|
||||
result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);
|
||||
|
||||
if (result != KERN_SUCCESS) {
|
||||
if (debug)
|
||||
printf("getregs: thread_get_state(%d) failed (%d)\n", tid, result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 40 32-bit registers on ppc, 16 on x86.
|
||||
// Output order is the same as the order in the ppc_thread_state/i386_thread_state struct.
|
||||
#if defined(__i386__)
|
||||
r = (unsigned int *)&state;
|
||||
registerArray = (*env)->NewLongArray(env, 8);
|
||||
primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
|
||||
primitiveArray[0] = r[0]; // eax
|
||||
primitiveArray[1] = r[2]; // ecx
|
||||
primitiveArray[2] = r[3]; // edx
|
||||
primitiveArray[3] = r[1]; // ebx
|
||||
primitiveArray[4] = r[7]; // esp
|
||||
primitiveArray[5] = r[6]; // ebp
|
||||
primitiveArray[6] = r[5]; // esi
|
||||
primitiveArray[7] = r[4]; // edi
|
||||
(*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
|
||||
#elif defined(__x86_64__)
|
||||
/* From AMD64ThreadContext.java
|
||||
public static final int R15 = 0;
|
||||
public static final int R14 = 1;
|
||||
public static final int R13 = 2;
|
||||
public static final int R12 = 3;
|
||||
public static final int R11 = 4;
|
||||
public static final int R10 = 5;
|
||||
public static final int R9 = 6;
|
||||
public static final int R8 = 7;
|
||||
public static final int RDI = 8;
|
||||
public static final int RSI = 9;
|
||||
public static final int RBP = 10;
|
||||
public static final int RBX = 11;
|
||||
public static final int RDX = 12;
|
||||
public static final int RCX = 13;
|
||||
public static final int RAX = 14;
|
||||
public static final int TRAPNO = 15;
|
||||
public static final int ERR = 16;
|
||||
public static final int RIP = 17;
|
||||
public static final int CS = 18;
|
||||
public static final int RFL = 19;
|
||||
public static final int RSP = 20;
|
||||
public static final int SS = 21;
|
||||
public static final int FS = 22;
|
||||
public static final int GS = 23;
|
||||
public static final int ES = 24;
|
||||
public static final int DS = 25;
|
||||
public static final int FSBASE = 26;
|
||||
public static final int GSBASE = 27;
|
||||
*/
|
||||
// 64 bit
|
||||
if (debug) printf("Getting threads for a 64-bit process\n");
|
||||
registerArray = (*env)->NewLongArray(env, 28);
|
||||
primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
|
||||
|
||||
primitiveArray[0] = state.__r15;
|
||||
primitiveArray[1] = state.__r14;
|
||||
primitiveArray[2] = state.__r13;
|
||||
primitiveArray[3] = state.__r12;
|
||||
primitiveArray[4] = state.__r11;
|
||||
primitiveArray[5] = state.__r10;
|
||||
primitiveArray[6] = state.__r9;
|
||||
primitiveArray[7] = state.__r8;
|
||||
primitiveArray[8] = state.__rdi;
|
||||
primitiveArray[9] = state.__rsi;
|
||||
primitiveArray[10] = state.__rbp;
|
||||
primitiveArray[11] = state.__rbx;
|
||||
primitiveArray[12] = state.__rdx;
|
||||
primitiveArray[13] = state.__rcx;
|
||||
primitiveArray[14] = state.__rax;
|
||||
primitiveArray[15] = 0; // trapno ?
|
||||
primitiveArray[16] = 0; // err ?
|
||||
primitiveArray[17] = state.__rip;
|
||||
primitiveArray[18] = state.__cs;
|
||||
primitiveArray[19] = state.__rflags;
|
||||
primitiveArray[20] = state.__rsp;
|
||||
primitiveArray[21] = 0; // We don't have SS
|
||||
primitiveArray[22] = state.__fs;
|
||||
primitiveArray[23] = state.__gs;
|
||||
primitiveArray[24] = 0;
|
||||
primitiveArray[25] = 0;
|
||||
primitiveArray[26] = 0;
|
||||
primitiveArray[27] = 0;
|
||||
|
||||
if (debug) printf("set registers\n");
|
||||
|
||||
(*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
return registerArray;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal
|
||||
* Method: translateTID0
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(JNIEnv *env, jobject this_obj, jint tid) {
|
||||
if (debug)
|
||||
printf("translateTID0 called on tid = 0x%x\n", (int)tid);
|
||||
|
||||
kern_return_t result;
|
||||
thread_t foreign_tid, usable_tid;
|
||||
mach_msg_type_name_t type;
|
||||
|
||||
foreign_tid = tid;
|
||||
|
||||
task_t gTask = getTask(env, this_obj);
|
||||
result = mach_port_extract_right(gTask, foreign_tid,
|
||||
MACH_MSG_TYPE_COPY_SEND,
|
||||
&usable_tid, &type);
|
||||
if (result != KERN_SUCCESS)
|
||||
return -1;
|
||||
|
||||
if (debug)
|
||||
printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
|
||||
|
||||
return (jint) usable_tid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(JNIEnv *env, jobject this_obj, jint jpid) {
|
||||
JNF_COCOA_ENTER(env);
|
||||
if (getenv("JAVA_SAPROC_DEBUG") != NULL)
|
||||
debug = JNI_TRUE;
|
||||
else
|
||||
debug = JNI_FALSE;
|
||||
if (debug) printf("attach0 called for jpid=%d\n", (int)jpid);
|
||||
|
||||
kern_return_t result;
|
||||
task_t gTask = 0;
|
||||
result = task_for_pid(mach_task_self(), jpid, &gTask);
|
||||
if (result != KERN_SUCCESS) {
|
||||
fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
|
||||
}
|
||||
putTask(env, this_obj, gTask);
|
||||
|
||||
id symbolicator = nil;
|
||||
id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
|
||||
if (jrsSymbolicator != nil) {
|
||||
id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
|
||||
symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
|
||||
}
|
||||
if (symbolicator != nil) {
|
||||
CFRetain(symbolicator); // pin symbolicator while in java heap
|
||||
}
|
||||
|
||||
putSymbolicator(env, this_obj, symbolicator);
|
||||
if (symbolicator == nil) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
|
||||
}
|
||||
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: detach0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(JNIEnv *env, jobject this_obj) {
|
||||
JNF_COCOA_ENTER(env);
|
||||
if (debug) printf("detach0 called\n");
|
||||
|
||||
task_t gTask = getTask(env, this_obj);
|
||||
mach_port_deallocate(mach_task_self(), gTask);
|
||||
id symbolicator = getSymbolicator(env, this_obj);
|
||||
if (symbolicator != nil) {
|
||||
CFRelease(symbolicator);
|
||||
}
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
77
hotspot/agent/src/os/bsd/Makefile
Normal file
77
hotspot/agent/src/os/bsd/Makefile
Normal file
|
@ -0,0 +1,77 @@
|
|||
#
|
||||
# Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
#
|
||||
|
||||
ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi )
|
||||
GCC = gcc
|
||||
|
||||
JAVAH = ${JAVA_HOME}/bin/javah
|
||||
|
||||
SOURCES = salibelf.c \
|
||||
symtab.c \
|
||||
libproc_impl.c \
|
||||
ps_proc.c \
|
||||
ps_core.c \
|
||||
BsdDebuggerLocal.c
|
||||
|
||||
INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]")
|
||||
|
||||
OBJS = $(SOURCES:.c=.o)
|
||||
|
||||
LIBS = -lutil -lthread_db
|
||||
|
||||
CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES)
|
||||
|
||||
LIBSA = $(ARCH)/libsaproc.so
|
||||
|
||||
all: $(LIBSA)
|
||||
|
||||
BsdDebuggerLocal.o: BsdDebuggerLocal.c
|
||||
$(JAVAH) -jni -classpath ../../../../../build/bsd-i586/hotspot/outputdir/bsd_i486_compiler2/generated/saclasses \
|
||||
sun.jvm.hotspot.debugger.x86.X86ThreadContext \
|
||||
sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
|
||||
$(GCC) $(CFLAGS) $<
|
||||
|
||||
.c.obj:
|
||||
$(GCC) $(CFLAGS)
|
||||
|
||||
ifndef LDNOMAP
|
||||
LFLAGS_LIBSA = -Xlinker --version-script=mapfile
|
||||
endif
|
||||
|
||||
$(LIBSA): $(OBJS) mapfile
|
||||
if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi
|
||||
$(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS)
|
||||
|
||||
test.o: $(LIBSA) test.c
|
||||
$(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c
|
||||
|
||||
test: test.o
|
||||
$(GCC) -o test test.o -L$(ARCH) -lsaproc $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(LIBSA)
|
||||
rm -f $(OBJS)
|
||||
rm -f test.o
|
||||
-rmdir $(ARCH)
|
||||
|
120
hotspot/agent/src/os/bsd/StubDebuggerLocal.c
Normal file
120
hotspot/agent/src/os/bsd/StubDebuggerLocal.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <jni.h>
|
||||
|
||||
#define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }
|
||||
#define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }
|
||||
#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}
|
||||
|
||||
static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: init0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0
|
||||
(JNIEnv *env, jclass cls) {
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
#ifdef _LP64
|
||||
return 8;
|
||||
#else
|
||||
return 4;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I
|
||||
(JNIEnv *env, jobject this_obj, jint jpid) {
|
||||
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: attach0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
|
||||
(JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: detach0
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByName0
|
||||
* Signature: (Ljava/lang/String;Ljava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0
|
||||
(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: lookupByAddress0
|
||||
* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
|
||||
(JNIEnv *env, jobject this_obj, jlong addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
|
||||
* Method: readBytesFromProcess0
|
||||
* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0
|
||||
(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
|
||||
(JNIEnv *env, jobject this_obj, jint lwp_id) {
|
||||
return 0;
|
||||
}
|
58
hotspot/agent/src/os/bsd/elfmacros.h
Normal file
58
hotspot/agent/src/os/bsd/elfmacros.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ELFMACROS_H_
|
||||
#define _ELFMACROS_H_
|
||||
|
||||
#define ELF_NHDR Elf_Note
|
||||
|
||||
#if defined(_LP64)
|
||||
#define ELF_EHDR Elf64_Ehdr
|
||||
#define ELF_SHDR Elf64_Shdr
|
||||
#define ELF_PHDR Elf64_Phdr
|
||||
#define ELF_SYM Elf64_Sym
|
||||
#define ELF_DYN Elf64_Dyn
|
||||
#define ELF_ADDR Elf64_Addr
|
||||
|
||||
#ifndef ELF_ST_TYPE
|
||||
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define ELF_EHDR Elf32_Ehdr
|
||||
#define ELF_SHDR Elf32_Shdr
|
||||
#define ELF_PHDR Elf32_Phdr
|
||||
#define ELF_SYM Elf32_Sym
|
||||
#define ELF_DYN Elf32_Dyn
|
||||
#define ELF_ADDR Elf32_Addr
|
||||
|
||||
#ifndef ELF_ST_TYPE
|
||||
#define ELF_ST_TYPE ELF32_ST_TYPE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _ELFMACROS_H_ */
|
127
hotspot/agent/src/os/bsd/libproc.h
Normal file
127
hotspot/agent/src/os/bsd/libproc.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBPROC_H_
|
||||
#define _LIBPROC_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <machine/reg.h>
|
||||
#include <proc_service.h>
|
||||
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
/*
|
||||
If _LP64 is defined ptrace.h should be taken from /usr/include/asm-sparc64
|
||||
otherwise it should be from /usr/include/asm-sparc
|
||||
These two files define pt_regs structure differently
|
||||
*/
|
||||
#ifdef _LP64
|
||||
#include "asm-sparc64/ptrace.h"
|
||||
#else
|
||||
#include "asm-sparc/ptrace.h"
|
||||
#endif
|
||||
|
||||
#endif //sparc or sparcv9
|
||||
|
||||
/************************************************************************************
|
||||
|
||||
0. This is very minimal subset of Solaris libproc just enough for current application.
|
||||
Please note that the bulk of the functionality is from proc_service interface. This
|
||||
adds Pgrab__ and some missing stuff. We hide the difference b/w live process and core
|
||||
file by this interface.
|
||||
|
||||
1. pthread_id is unique. We store this in OSThread::_pthread_id in JVM code.
|
||||
|
||||
2. All threads see the same pid when they call getpid().
|
||||
We used to save the result of ::getpid() call in OSThread::_thread_id.
|
||||
Because gettid returns actual pid of thread (lwp id), this is
|
||||
unique again. We therefore use OSThread::_thread_id as unique identifier.
|
||||
|
||||
3. There is a unique LWP id under both thread libraries. libthread_db maps pthread_id
|
||||
to its underlying lwp_id under both the thread libraries. thread_info.lwp_id stores
|
||||
lwp_id of the thread. The lwp id is nothing but the actual pid of clone'd processes. But
|
||||
unfortunately libthread_db does not work very well for core dumps. So, we get pthread_id
|
||||
only for processes. For core dumps, we don't use libthread_db at all (like gdb).
|
||||
|
||||
4. ptrace operates on this LWP id under both the thread libraries. When we say 'pid' for
|
||||
ptrace call, we refer to lwp_id of the thread.
|
||||
|
||||
5. for core file, we parse ELF files and read data from them. For processes we use
|
||||
combination of ptrace and /proc calls.
|
||||
|
||||
*************************************************************************************/
|
||||
|
||||
// This C bool type must be int for compatibility with BSD calls and
|
||||
// it would be a mistake to equivalence it to C++ bool on many platforms
|
||||
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
struct ps_prochandle;
|
||||
|
||||
// attach to a process
|
||||
struct ps_prochandle* Pgrab(pid_t pid);
|
||||
|
||||
// attach to a core dump
|
||||
struct ps_prochandle* Pgrab_core(const char* execfile, const char* corefile);
|
||||
|
||||
// release a process or core
|
||||
void Prelease(struct ps_prochandle* ph);
|
||||
|
||||
// functions not directly available in Solaris libproc
|
||||
|
||||
// initialize libproc (call this only once per app)
|
||||
// pass true to make library verbose
|
||||
bool init_libproc(bool verbose);
|
||||
|
||||
// get number of threads
|
||||
int get_num_threads(struct ps_prochandle* ph);
|
||||
|
||||
// get lwp_id of n'th thread
|
||||
lwpid_t get_lwp_id(struct ps_prochandle* ph, int index);
|
||||
|
||||
// get regs for a given lwp
|
||||
bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lid, struct reg* regs);
|
||||
|
||||
// get number of shared objects
|
||||
int get_num_libs(struct ps_prochandle* ph);
|
||||
|
||||
// get name of n'th lib
|
||||
const char* get_lib_name(struct ps_prochandle* ph, int index);
|
||||
|
||||
// get base of lib
|
||||
uintptr_t get_lib_base(struct ps_prochandle* ph, int index);
|
||||
|
||||
// returns true if given library is found in lib list
|
||||
bool find_lib(struct ps_prochandle* ph, const char *lib_name);
|
||||
|
||||
// symbol lookup
|
||||
uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,
|
||||
const char* sym_name);
|
||||
|
||||
// address->nearest symbol lookup. return NULL for no symbol
|
||||
const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset);
|
||||
|
||||
#endif //__LIBPROC_H_
|
452
hotspot/agent/src/os/bsd/libproc_impl.c
Normal file
452
hotspot/agent/src/os/bsd/libproc_impl.c
Normal file
|
@ -0,0 +1,452 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <thread_db.h>
|
||||
#include "libproc_impl.h"
|
||||
|
||||
static const char* alt_root = NULL;
|
||||
static int alt_root_len = -1;
|
||||
|
||||
#define SA_ALTROOT "SA_ALTROOT"
|
||||
|
||||
static void init_alt_root() {
|
||||
if (alt_root_len == -1) {
|
||||
alt_root = getenv(SA_ALTROOT);
|
||||
if (alt_root) {
|
||||
alt_root_len = strlen(alt_root);
|
||||
} else {
|
||||
alt_root_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pathmap_open(const char* name) {
|
||||
int fd;
|
||||
char alt_path[PATH_MAX + 1];
|
||||
|
||||
init_alt_root();
|
||||
fd = open(name, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (alt_root_len > 0) {
|
||||
strcpy(alt_path, alt_root);
|
||||
strcat(alt_path, name);
|
||||
fd = open(alt_path, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
print_debug("path %s substituted for %s\n", alt_path, name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (strrchr(name, '/')) {
|
||||
strcpy(alt_path, alt_root);
|
||||
strcat(alt_path, strrchr(name, '/'));
|
||||
fd = open(alt_path, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
print_debug("path %s substituted for %s\n", alt_path, name);
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool _libsaproc_debug;
|
||||
|
||||
void print_debug(const char* format,...) {
|
||||
if (_libsaproc_debug) {
|
||||
va_list alist;
|
||||
|
||||
va_start(alist, format);
|
||||
fputs("libsaproc DEBUG: ", stderr);
|
||||
vfprintf(stderr, format, alist);
|
||||
va_end(alist);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_debug() {
|
||||
return _libsaproc_debug;
|
||||
}
|
||||
|
||||
// initialize libproc
|
||||
bool init_libproc(bool debug) {
|
||||
// init debug mode
|
||||
_libsaproc_debug = debug;
|
||||
|
||||
// initialize the thread_db library
|
||||
if (td_init() != TD_OK) {
|
||||
print_debug("libthread_db's td_init failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void destroy_lib_info(struct ps_prochandle* ph) {
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
lib_info *next = lib->next;
|
||||
if (lib->symtab) {
|
||||
destroy_symtab(lib->symtab);
|
||||
}
|
||||
free(lib);
|
||||
lib = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_thread_info(struct ps_prochandle* ph) {
|
||||
thread_info* thr = ph->threads;
|
||||
while (thr) {
|
||||
thread_info *next = thr->next;
|
||||
free(thr);
|
||||
thr = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ps_prochandle cleanup
|
||||
|
||||
// ps_prochandle cleanup
|
||||
void Prelease(struct ps_prochandle* ph) {
|
||||
// do the "derived class" clean-up first
|
||||
ph->ops->release(ph);
|
||||
destroy_lib_info(ph);
|
||||
destroy_thread_info(ph);
|
||||
free(ph);
|
||||
}
|
||||
|
||||
lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) {
|
||||
return add_lib_info_fd(ph, libname, -1, base);
|
||||
}
|
||||
|
||||
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) {
|
||||
lib_info* newlib;
|
||||
|
||||
if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {
|
||||
print_debug("can't allocate memory for lib_info\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(newlib->name, libname, sizeof(newlib->name));
|
||||
newlib->base = base;
|
||||
|
||||
if (fd == -1) {
|
||||
if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {
|
||||
print_debug("can't open shared object %s\n", newlib->name);
|
||||
free(newlib);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
newlib->fd = fd;
|
||||
}
|
||||
|
||||
// check whether we have got an ELF file. /proc/<pid>/map
|
||||
// gives out all file mappings and not just shared objects
|
||||
if (is_elf_file(newlib->fd) == false) {
|
||||
close(newlib->fd);
|
||||
free(newlib);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newlib->symtab = build_symtab(newlib->fd);
|
||||
if (newlib->symtab == NULL) {
|
||||
print_debug("symbol table build failed for %s\n", newlib->name);
|
||||
}
|
||||
else {
|
||||
print_debug("built symbol table for %s\n", newlib->name);
|
||||
}
|
||||
|
||||
// even if symbol table building fails, we add the lib_info.
|
||||
// This is because we may need to read from the ELF file for core file
|
||||
// address read functionality. lookup_symbol checks for NULL symtab.
|
||||
if (ph->libs) {
|
||||
ph->lib_tail->next = newlib;
|
||||
ph->lib_tail = newlib;
|
||||
} else {
|
||||
ph->libs = ph->lib_tail = newlib;
|
||||
}
|
||||
ph->num_libs++;
|
||||
|
||||
return newlib;
|
||||
}
|
||||
|
||||
// lookup for a specific symbol
|
||||
uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,
|
||||
const char* sym_name) {
|
||||
// ignore object_name. search in all libraries
|
||||
// FIXME: what should we do with object_name?? The library names are obtained
|
||||
// by parsing /proc/<pid>/maps, which may not be the same as object_name.
|
||||
// What we need is a utility to map object_name to real file name, something
|
||||
// dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For
|
||||
// now, we just ignore object_name and do a global search for the symbol.
|
||||
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
if (lib->symtab) {
|
||||
uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL);
|
||||
if (res) return res;
|
||||
}
|
||||
lib = lib->next;
|
||||
}
|
||||
|
||||
print_debug("lookup failed for symbol '%s' in obj '%s'\n",
|
||||
sym_name, object_name);
|
||||
return (uintptr_t) NULL;
|
||||
}
|
||||
|
||||
|
||||
const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) {
|
||||
const char* res = NULL;
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
if (lib->symtab && addr >= lib->base) {
|
||||
res = nearest_symbol(lib->symtab, addr - lib->base, poffset);
|
||||
if (res) return res;
|
||||
}
|
||||
lib = lib->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// add a thread to ps_prochandle
|
||||
thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
|
||||
thread_info* newthr;
|
||||
if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) {
|
||||
print_debug("can't allocate memory for thread_info\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// initialize thread info
|
||||
newthr->pthread_id = pthread_id;
|
||||
newthr->lwp_id = lwp_id;
|
||||
|
||||
// add new thread to the list
|
||||
newthr->next = ph->threads;
|
||||
ph->threads = newthr;
|
||||
ph->num_threads++;
|
||||
return newthr;
|
||||
}
|
||||
|
||||
|
||||
// struct used for client data from thread_db callback
|
||||
struct thread_db_client_data {
|
||||
struct ps_prochandle* ph;
|
||||
thread_info_callback callback;
|
||||
};
|
||||
|
||||
// callback function for libthread_db
|
||||
static int thread_db_callback(const td_thrhandle_t *th_p, void *data) {
|
||||
struct thread_db_client_data* ptr = (struct thread_db_client_data*) data;
|
||||
td_thrinfo_t ti;
|
||||
td_err_e err;
|
||||
|
||||
memset(&ti, 0, sizeof(ti));
|
||||
err = td_thr_get_info(th_p, &ti);
|
||||
if (err != TD_OK) {
|
||||
print_debug("libthread_db : td_thr_get_info failed, can't get thread info\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
print_debug("thread_db : pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid);
|
||||
|
||||
if (ptr->callback(ptr->ph, (pthread_t)ti.ti_tid, ti.ti_lid) != true)
|
||||
return TD_ERR;
|
||||
|
||||
return TD_OK;
|
||||
}
|
||||
|
||||
// read thread_info using libthread_db
|
||||
bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) {
|
||||
struct thread_db_client_data mydata;
|
||||
td_thragent_t* thread_agent = NULL;
|
||||
if (td_ta_new(ph, &thread_agent) != TD_OK) {
|
||||
print_debug("can't create libthread_db agent\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
mydata.ph = ph;
|
||||
mydata.callback = cb;
|
||||
|
||||
// we use libthread_db iterator to iterate thru list of threads.
|
||||
if (td_ta_thr_iter(thread_agent, thread_db_callback, &mydata,
|
||||
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
|
||||
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS) != TD_OK) {
|
||||
td_ta_delete(thread_agent);
|
||||
return false;
|
||||
}
|
||||
|
||||
// delete thread agent
|
||||
td_ta_delete(thread_agent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// get number of threads
|
||||
int get_num_threads(struct ps_prochandle* ph) {
|
||||
return ph->num_threads;
|
||||
}
|
||||
|
||||
// get lwp_id of n'th thread
|
||||
lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) {
|
||||
int count = 0;
|
||||
thread_info* thr = ph->threads;
|
||||
while (thr) {
|
||||
if (count == index) {
|
||||
return thr->lwp_id;
|
||||
}
|
||||
count++;
|
||||
thr = thr->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get regs for a given lwp
|
||||
bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) {
|
||||
return ph->ops->get_lwp_regs(ph, lwp_id, regs);
|
||||
}
|
||||
|
||||
// get number of shared objects
|
||||
int get_num_libs(struct ps_prochandle* ph) {
|
||||
return ph->num_libs;
|
||||
}
|
||||
|
||||
// get name of n'th solib
|
||||
const char* get_lib_name(struct ps_prochandle* ph, int index) {
|
||||
int count = 0;
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
if (count == index) {
|
||||
return lib->name;
|
||||
}
|
||||
count++;
|
||||
lib = lib->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get base address of a lib
|
||||
uintptr_t get_lib_base(struct ps_prochandle* ph, int index) {
|
||||
int count = 0;
|
||||
lib_info* lib = ph->libs;
|
||||
while (lib) {
|
||||
if (count == index) {
|
||||
return lib->base;
|
||||
}
|
||||
count++;
|
||||
lib = lib->next;
|
||||
}
|
||||
return (uintptr_t)NULL;
|
||||
}
|
||||
|
||||
bool find_lib(struct ps_prochandle* ph, const char *lib_name) {
|
||||
lib_info *p = ph->libs;
|
||||
while (p) {
|
||||
if (strcmp(p->name, lib_name) == 0) {
|
||||
return true;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// proc service functions
|
||||
|
||||
// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table
|
||||
// of the load object object_name in the target process identified by ph.
|
||||
// It returns the symbol's value as an address in the target process in
|
||||
// *sym_addr.
|
||||
|
||||
ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,
|
||||
const char *sym_name, psaddr_t *sym_addr) {
|
||||
*sym_addr = (psaddr_t) lookup_symbol(ph, object_name, sym_name);
|
||||
return (*sym_addr ? PS_OK : PS_NOSYM);
|
||||
}
|
||||
|
||||
// read "size" bytes info "buf" from address "addr"
|
||||
ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr,
|
||||
void *buf, size_t size) {
|
||||
return ph->ops->p_pread(ph, (uintptr_t) addr, buf, size)? PS_OK: PS_ERR;
|
||||
}
|
||||
|
||||
// write "size" bytes of data to debuggee at address "addr"
|
||||
ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr,
|
||||
const void *buf, size_t size) {
|
||||
return ph->ops->p_pwrite(ph, (uintptr_t)addr, buf, size)? PS_OK: PS_ERR;
|
||||
}
|
||||
|
||||
// fill in ptrace_lwpinfo for lid
|
||||
ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) {
|
||||
return ph->ops->get_lwp_info(ph, lwp_id, linfo)? PS_OK: PS_ERR;
|
||||
}
|
||||
|
||||
// needed for when libthread_db is compiled with TD_DEBUG defined
|
||||
void
|
||||
ps_plog (const char *format, ...)
|
||||
{
|
||||
va_list alist;
|
||||
|
||||
va_start(alist, format);
|
||||
vfprintf(stderr, format, alist);
|
||||
va_end(alist);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Functions below this point are not yet implemented. They are here only
|
||||
// to make the linker happy.
|
||||
|
||||
ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lid, const prfpregset_t *fpregs) {
|
||||
print_debug("ps_lsetfpregs not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lid, const prgregset_t gregset) {
|
||||
print_debug("ps_lsetregs not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lid, prfpregset_t *fpregs) {
|
||||
print_debug("ps_lgetfpregs not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset) {
|
||||
print_debug("ps_lgetfpregs not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_lstop(struct ps_prochandle *ph, lwpid_t lid) {
|
||||
print_debug("ps_lstop not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
ps_err_e ps_pcontinue(struct ps_prochandle *ph) {
|
||||
print_debug("ps_pcontinue not implemented\n");
|
||||
return PS_OK;
|
||||
}
|
130
hotspot/agent/src/os/bsd/libproc_impl.h
Normal file
130
hotspot/agent/src/os/bsd/libproc_impl.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBPROC_IMPL_H_
|
||||
#define _LIBPROC_IMPL_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include "libproc.h"
|
||||
#include "symtab.h"
|
||||
|
||||
// data structures in this file mimic those of Solaris 8.0 - libproc's Pcontrol.h
|
||||
|
||||
#define BUF_SIZE (PATH_MAX + NAME_MAX + 1)
|
||||
|
||||
// list of shared objects
|
||||
typedef struct lib_info {
|
||||
char name[BUF_SIZE];
|
||||
uintptr_t base;
|
||||
struct symtab* symtab;
|
||||
int fd; // file descriptor for lib
|
||||
struct lib_info* next;
|
||||
} lib_info;
|
||||
|
||||
// list of threads
|
||||
typedef struct thread_info {
|
||||
lwpid_t lwp_id;
|
||||
pthread_t pthread_id; // not used cores, always -1
|
||||
struct reg regs; // not for process, core uses for caching regset
|
||||
struct thread_info* next;
|
||||
} thread_info;
|
||||
|
||||
// list of virtual memory maps
|
||||
typedef struct map_info {
|
||||
int fd; // file descriptor
|
||||
off_t offset; // file offset of this mapping
|
||||
uintptr_t vaddr; // starting virtual address
|
||||
size_t memsz; // size of the mapping
|
||||
struct map_info* next;
|
||||
} map_info;
|
||||
|
||||
// vtable for ps_prochandle
|
||||
typedef struct ps_prochandle_ops {
|
||||
// "derived class" clean-up
|
||||
void (*release)(struct ps_prochandle* ph);
|
||||
// read from debuggee
|
||||
bool (*p_pread)(struct ps_prochandle *ph,
|
||||
uintptr_t addr, char *buf, size_t size);
|
||||
// write into debuggee
|
||||
bool (*p_pwrite)(struct ps_prochandle *ph,
|
||||
uintptr_t addr, const char *buf , size_t size);
|
||||
// get integer regset of a thread
|
||||
bool (*get_lwp_regs)(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs);
|
||||
// get info on thread
|
||||
bool (*get_lwp_info)(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo);
|
||||
} ps_prochandle_ops;
|
||||
|
||||
// the ps_prochandle
|
||||
|
||||
struct core_data {
|
||||
int core_fd; // file descriptor of core file
|
||||
int exec_fd; // file descriptor of exec file
|
||||
int interp_fd; // file descriptor of interpreter (ld-elf.so.1)
|
||||
// part of the class sharing workaround
|
||||
int classes_jsa_fd; // file descriptor of class share archive
|
||||
uintptr_t dynamic_addr; // address of dynamic section of a.out
|
||||
uintptr_t ld_base_addr; // base address of ld.so
|
||||
size_t num_maps; // number of maps.
|
||||
map_info* maps; // maps in a linked list
|
||||
// part of the class sharing workaround
|
||||
map_info* class_share_maps;// class share maps in a linked list
|
||||
map_info** map_array; // sorted (by vaddr) array of map_info pointers
|
||||
};
|
||||
|
||||
struct ps_prochandle {
|
||||
ps_prochandle_ops* ops; // vtable ptr
|
||||
pid_t pid;
|
||||
int num_libs;
|
||||
lib_info* libs; // head of lib list
|
||||
lib_info* lib_tail; // tail of lib list - to append at the end
|
||||
int num_threads;
|
||||
thread_info* threads; // head of thread list
|
||||
struct core_data* core; // data only used for core dumps, NULL for process
|
||||
};
|
||||
|
||||
int pathmap_open(const char* name);
|
||||
|
||||
void print_debug(const char* format,...);
|
||||
bool is_debug();
|
||||
|
||||
typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lwpid_t lwpid);
|
||||
|
||||
// reads thread info using libthread_db and calls above callback for each thread
|
||||
bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb);
|
||||
|
||||
// adds a new shared object to lib list, returns NULL on failure
|
||||
lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base);
|
||||
|
||||
// adds a new shared object to lib list, supply open lib file descriptor as well
|
||||
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd,
|
||||
uintptr_t base);
|
||||
|
||||
// adds a new thread to threads list, returns NULL on failure
|
||||
thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id);
|
||||
|
||||
// a test for ELF signature without using libelf
|
||||
bool is_elf_file(int fd);
|
||||
|
||||
#endif //_LIBPROC_IMPL_H_
|
66
hotspot/agent/src/os/bsd/mapfile
Normal file
66
hotspot/agent/src/os/bsd/mapfile
Normal file
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
#
|
||||
|
||||
# Define public interface.
|
||||
|
||||
SUNWprivate_1.1 {
|
||||
global:
|
||||
|
||||
# native methods of BsdDebuggerLocal class
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0;
|
||||
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0;
|
||||
|
||||
# proc_service.h functions - to be used by libthread_db
|
||||
ps_getpid;
|
||||
ps_pglobal_lookup;
|
||||
ps_pread;
|
||||
ps_pwrite;
|
||||
ps_lsetfpregs;
|
||||
ps_lsetregs;
|
||||
ps_lgetfpregs;
|
||||
ps_lgetregs;
|
||||
ps_lcontinue;
|
||||
ps_lgetxmmregs;
|
||||
ps_lsetxmmregs;
|
||||
ps_lstop;
|
||||
ps_linfo;
|
||||
|
||||
# used by attach test program
|
||||
init_libproc;
|
||||
Pgrab;
|
||||
Pgrab_core;
|
||||
Prelease;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
1023
hotspot/agent/src/os/bsd/ps_core.c
Normal file
1023
hotspot/agent/src/os/bsd/ps_core.c
Normal file
File diff suppressed because it is too large
Load diff
444
hotspot/agent/src/os/bsd/ps_proc.c
Normal file
444
hotspot/agent/src/os/bsd/ps_proc.c
Normal file
|
@ -0,0 +1,444 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/user.h>
|
||||
#include <elf.h>
|
||||
#include <sys/elf_common.h>
|
||||
#include <sys/link_elf.h>
|
||||
#include <libutil.h>
|
||||
#include "libproc_impl.h"
|
||||
#include "elfmacros.h"
|
||||
|
||||
// This file has the libproc implementation specific to live process
|
||||
// For core files, refer to ps_core.c
|
||||
|
||||
static inline uintptr_t align(uintptr_t ptr, size_t size) {
|
||||
return (ptr & ~(size - 1));
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// ptrace functions
|
||||
// ---------------------------------------------
|
||||
|
||||
// read "size" bytes of data from "addr" within the target process.
|
||||
// unlike the standard ptrace() function, process_read_data() can handle
|
||||
// unaligned address - alignment check, if required, should be done
|
||||
// before calling process_read_data.
|
||||
|
||||
static bool process_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) {
|
||||
int rslt;
|
||||
size_t i, words;
|
||||
uintptr_t end_addr = addr + size;
|
||||
uintptr_t aligned_addr = align(addr, sizeof(int));
|
||||
|
||||
if (aligned_addr != addr) {
|
||||
char *ptr = (char *)&rslt;
|
||||
errno = 0;
|
||||
rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0);
|
||||
if (errno) {
|
||||
print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr);
|
||||
return false;
|
||||
}
|
||||
for (; aligned_addr != addr; aligned_addr++, ptr++);
|
||||
for (; ((intptr_t)aligned_addr % sizeof(int)) && aligned_addr < end_addr;
|
||||
aligned_addr++)
|
||||
*(buf++) = *(ptr++);
|
||||
}
|
||||
|
||||
words = (end_addr - aligned_addr) / sizeof(int);
|
||||
|
||||
// assert((intptr_t)aligned_addr % sizeof(int) == 0);
|
||||
for (i = 0; i < words; i++) {
|
||||
errno = 0;
|
||||
rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0);
|
||||
if (errno) {
|
||||
print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr);
|
||||
return false;
|
||||
}
|
||||
*(int *)buf = rslt;
|
||||
buf += sizeof(int);
|
||||
aligned_addr += sizeof(int);
|
||||
}
|
||||
|
||||
if (aligned_addr != end_addr) {
|
||||
char *ptr = (char *)&rslt;
|
||||
errno = 0;
|
||||
rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0);
|
||||
if (errno) {
|
||||
print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr);
|
||||
return false;
|
||||
}
|
||||
for (; aligned_addr != end_addr; aligned_addr++)
|
||||
*(buf++) = *(ptr++);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// null implementation for write
|
||||
static bool process_write_data(struct ps_prochandle* ph,
|
||||
uintptr_t addr, const char *buf , size_t size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// "user" should be a pointer to a reg
|
||||
static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct reg *user) {
|
||||
// we have already attached to all thread 'pid's, just use ptrace call
|
||||
// to get regset now. Note that we don't cache regset upfront for processes.
|
||||
if (ptrace(PT_GETREGS, pid, (caddr_t) user, 0) < 0) {
|
||||
print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// fill in ptrace_lwpinfo for lid
|
||||
static bool process_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) {
|
||||
errno = 0;
|
||||
ptrace(PT_LWPINFO, lwp_id, linfo, sizeof(struct ptrace_lwpinfo));
|
||||
|
||||
return (errno == 0)? true: false;
|
||||
}
|
||||
|
||||
// attach to a process/thread specified by "pid"
|
||||
static bool ptrace_attach(pid_t pid) {
|
||||
if (ptrace(PT_ATTACH, pid, NULL, 0) < 0) {
|
||||
print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid);
|
||||
return false;
|
||||
} else {
|
||||
int ret;
|
||||
int status;
|
||||
do {
|
||||
// Wait for debuggee to stop.
|
||||
ret = waitpid(pid, &status, 0);
|
||||
if (ret >= 0) {
|
||||
if (WIFSTOPPED(status)) {
|
||||
// Debuggee stopped.
|
||||
return true;
|
||||
} else {
|
||||
print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
break;
|
||||
case ECHILD:
|
||||
print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
|
||||
break;
|
||||
case EINVAL:
|
||||
print_debug("waitpid() failed. Invalid options argument.\n");
|
||||
break;
|
||||
default:
|
||||
print_debug("waitpid() failed. Unexpected error %d\n",errno);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} while(true);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------
|
||||
// functions for obtaining library information
|
||||
// -------------------------------------------------------
|
||||
|
||||
// callback for read_thread_info
|
||||
static bool add_new_thread(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
|
||||
return add_thread_info(ph, pthread_id, lwp_id) != NULL;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__) && __FreeBSD_version < 701000
|
||||
/*
|
||||
* TEXT_START_ADDR from binutils/ld/emulparams/<arch_spec>.sh
|
||||
* Not the most robust but good enough.
|
||||
*/
|
||||
|
||||
#if defined(amd64) || defined(x86_64)
|
||||
#define TEXT_START_ADDR 0x400000
|
||||
#elif defined(i386)
|
||||
#define TEXT_START_ADDR 0x8048000
|
||||
#else
|
||||
#error TEXT_START_ADDR not defined
|
||||
#endif
|
||||
|
||||
#define BUF_SIZE (PATH_MAX + NAME_MAX + 1)
|
||||
|
||||
uintptr_t linkmap_addr(struct ps_prochandle *ph) {
|
||||
uintptr_t ehdr_addr, phdr_addr, dyn_addr, dmap_addr, lmap_addr;
|
||||
ELF_EHDR ehdr;
|
||||
ELF_PHDR *phdrs, *phdr;
|
||||
ELF_DYN *dyns, *dyn;
|
||||
struct r_debug dmap;
|
||||
unsigned long hdrs_size;
|
||||
unsigned int i;
|
||||
|
||||
/* read ELF_EHDR at TEXT_START_ADDR and validate */
|
||||
|
||||
ehdr_addr = (uintptr_t)TEXT_START_ADDR;
|
||||
|
||||
if (process_read_data(ph, ehdr_addr, (char *)&ehdr, sizeof(ehdr)) != true) {
|
||||
print_debug("process_read_data failed for ehdr_addr %p\n", ehdr_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!IS_ELF(ehdr) ||
|
||||
ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
|
||||
ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
|
||||
ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
|
||||
ehdr.e_phentsize != sizeof(ELF_PHDR) ||
|
||||
ehdr.e_version != ELF_TARG_VER ||
|
||||
ehdr.e_machine != ELF_TARG_MACH) {
|
||||
print_debug("not an ELF_EHDR at %p\n", ehdr_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* allocate space for all ELF_PHDR's and read */
|
||||
|
||||
phdr_addr = ehdr_addr + ehdr.e_phoff;
|
||||
hdrs_size = ehdr.e_phnum * sizeof(ELF_PHDR);
|
||||
|
||||
if ((phdrs = malloc(hdrs_size)) == NULL)
|
||||
return (0);
|
||||
|
||||
if (process_read_data(ph, phdr_addr, (char *)phdrs, hdrs_size) != true) {
|
||||
print_debug("process_read_data failed for phdr_addr %p\n", phdr_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* find PT_DYNAMIC section */
|
||||
|
||||
for (i = 0, phdr = phdrs; i < ehdr.e_phnum; i++, phdr++) {
|
||||
if (phdr->p_type == PT_DYNAMIC)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= ehdr.e_phnum) {
|
||||
print_debug("PT_DYNAMIC section not found!\n");
|
||||
free(phdrs);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* allocate space and read in ELF_DYN headers */
|
||||
|
||||
dyn_addr = phdr->p_vaddr;
|
||||
hdrs_size = phdr->p_memsz;
|
||||
free(phdrs);
|
||||
|
||||
if ((dyns = malloc(hdrs_size)) == NULL)
|
||||
return (0);
|
||||
|
||||
if (process_read_data(ph, dyn_addr, (char *)dyns, hdrs_size) != true) {
|
||||
print_debug("process_read_data failed for dyn_addr %p\n", dyn_addr);
|
||||
free(dyns);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* find DT_DEBUG */
|
||||
|
||||
dyn = dyns;
|
||||
while (dyn->d_tag != DT_DEBUG && dyn->d_tag != DT_NULL) {
|
||||
dyn++;
|
||||
}
|
||||
|
||||
if (dyn->d_tag != DT_DEBUG) {
|
||||
print_debug("failed to find DT_DEBUG\n");
|
||||
free(dyns);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* read struct r_debug into dmap */
|
||||
|
||||
dmap_addr = (uintptr_t)dyn->d_un.d_ptr;
|
||||
free(dyns);
|
||||
|
||||
if (process_read_data(ph, dmap_addr, (char *)&dmap, sizeof(dmap)) != true) {
|
||||
print_debug("process_read_data failed for dmap_addr %p\n", dmap_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
lmap_addr = (uintptr_t)dmap.r_map;
|
||||
|
||||
return (lmap_addr);
|
||||
}
|
||||
#endif // __FreeBSD__ && __FreeBSD_version < 701000
|
||||
|
||||
static bool read_lib_info(struct ps_prochandle* ph) {
|
||||
#if defined(__FreeBSD__) && __FreeBSD_version >= 701000
|
||||
struct kinfo_vmentry *freep, *kve;
|
||||
int i, cnt;
|
||||
|
||||
freep = kinfo_getvmmap(ph->pid, &cnt);
|
||||
if (freep == NULL) {
|
||||
print_debug("can't get vm map for pid\n", ph->pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
kve = &freep[i];
|
||||
if ((kve->kve_flags & KVME_FLAG_COW) &&
|
||||
kve->kve_path != NULL &&
|
||||
strlen(kve->kve_path) > 0) {
|
||||
|
||||
if (find_lib(ph, kve->kve_path) == false) {
|
||||
lib_info* lib;
|
||||
if ((lib = add_lib_info(ph, kve->kve_path,
|
||||
(uintptr_t) kve->kve_start)) == NULL)
|
||||
continue; // ignore, add_lib_info prints error
|
||||
|
||||
// we don't need to keep the library open, symtab is already
|
||||
// built. Only for core dump we need to keep the fd open.
|
||||
close(lib->fd);
|
||||
lib->fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(freep);
|
||||
|
||||
return true;
|
||||
#else
|
||||
char *l_name;
|
||||
struct link_map *lmap;
|
||||
uintptr_t lmap_addr;
|
||||
|
||||
if ((l_name = malloc(BUF_SIZE)) == NULL)
|
||||
return false;
|
||||
|
||||
if ((lmap = malloc(sizeof(*lmap))) == NULL) {
|
||||
free(l_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
lmap_addr = linkmap_addr(ph);
|
||||
|
||||
if (lmap_addr == 0) {
|
||||
free(l_name);
|
||||
free(lmap);
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
if (process_read_data(ph, lmap_addr, (char *)lmap, sizeof(*lmap)) != true) {
|
||||
print_debug("process_read_data failed for lmap_addr %p\n", lmap_addr);
|
||||
free (l_name);
|
||||
free (lmap);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (process_read_data(ph, (uintptr_t)lmap->l_name, l_name,
|
||||
BUF_SIZE) != true) {
|
||||
print_debug("process_read_data failed for lmap->l_name %p\n",
|
||||
lmap->l_name);
|
||||
free (l_name);
|
||||
free (lmap);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (find_lib(ph, l_name) == false) {
|
||||
lib_info* lib;
|
||||
if ((lib = add_lib_info(ph, l_name,
|
||||
(uintptr_t) lmap->l_addr)) == NULL)
|
||||
continue; // ignore, add_lib_info prints error
|
||||
|
||||
// we don't need to keep the library open, symtab is already
|
||||
// built. Only for core dump we need to keep the fd open.
|
||||
close(lib->fd);
|
||||
lib->fd = -1;
|
||||
}
|
||||
lmap_addr = (uintptr_t)lmap->l_next;
|
||||
} while (lmap->l_next != NULL);
|
||||
|
||||
free (l_name);
|
||||
free (lmap);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// detach a given pid
|
||||
static bool ptrace_detach(pid_t pid) {
|
||||
if (pid && ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) {
|
||||
print_debug("ptrace(PTRACE_DETACH, ..) failed for %d\n", pid);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void process_cleanup(struct ps_prochandle* ph) {
|
||||
ptrace_detach(ph->pid);
|
||||
}
|
||||
|
||||
static ps_prochandle_ops process_ops = {
|
||||
.release= process_cleanup,
|
||||
.p_pread= process_read_data,
|
||||
.p_pwrite= process_write_data,
|
||||
.get_lwp_regs= process_get_lwp_regs,
|
||||
.get_lwp_info= process_get_lwp_info
|
||||
};
|
||||
|
||||
// attach to the process. One and only one exposed stuff
|
||||
struct ps_prochandle* Pgrab(pid_t pid) {
|
||||
struct ps_prochandle* ph = NULL;
|
||||
thread_info* thr = NULL;
|
||||
|
||||
if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) {
|
||||
print_debug("can't allocate memory for ps_prochandle\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ptrace_attach(pid) != true) {
|
||||
free(ph);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// initialize ps_prochandle
|
||||
ph->pid = pid;
|
||||
|
||||
// initialize vtable
|
||||
ph->ops = &process_ops;
|
||||
|
||||
// read library info and symbol tables, must do this before attaching threads,
|
||||
// as the symbols in the pthread library will be used to figure out
|
||||
// the list of threads within the same process.
|
||||
if (read_lib_info(ph) != true) {
|
||||
ptrace_detach(pid);
|
||||
free(ph);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read thread info
|
||||
read_thread_info(ph, add_new_thread);
|
||||
|
||||
return ph;
|
||||
}
|
126
hotspot/agent/src/os/bsd/salibelf.c
Normal file
126
hotspot/agent/src/os/bsd/salibelf.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "salibelf.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void print_debug(const char*,...);
|
||||
|
||||
// ELF file parsing helpers. Note that we do *not* use libelf here.
|
||||
int read_elf_header(int fd, ELF_EHDR* ehdr) {
|
||||
if (pread(fd, ehdr, sizeof (ELF_EHDR), 0) != sizeof (ELF_EHDR) ||
|
||||
memcmp(&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 ||
|
||||
ehdr->e_version != EV_CURRENT) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool is_elf_file(int fd) {
|
||||
ELF_EHDR ehdr;
|
||||
return read_elf_header(fd, &ehdr);
|
||||
}
|
||||
|
||||
// read program header table of an ELF file
|
||||
ELF_PHDR* read_program_header_table(int fd, ELF_EHDR* hdr) {
|
||||
ELF_PHDR* phbuf = 0;
|
||||
// allocate memory for program header table
|
||||
size_t nbytes = hdr->e_phnum * hdr->e_phentsize;
|
||||
|
||||
if ((phbuf = (ELF_PHDR*) malloc(nbytes)) == NULL) {
|
||||
print_debug("can't allocate memory for reading program header table\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pread(fd, phbuf, nbytes, hdr->e_phoff) != nbytes) {
|
||||
print_debug("ELF file is truncated! can't read program header table\n");
|
||||
free(phbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return phbuf;
|
||||
}
|
||||
|
||||
// read section header table of an ELF file
|
||||
ELF_SHDR* read_section_header_table(int fd, ELF_EHDR* hdr) {
|
||||
ELF_SHDR* shbuf = 0;
|
||||
// allocate memory for section header table
|
||||
size_t nbytes = hdr->e_shnum * hdr->e_shentsize;
|
||||
|
||||
if ((shbuf = (ELF_SHDR*) malloc(nbytes)) == NULL) {
|
||||
print_debug("can't allocate memory for reading section header table\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pread(fd, shbuf, nbytes, hdr->e_shoff) != nbytes) {
|
||||
print_debug("ELF file is truncated! can't read section header table\n");
|
||||
free(shbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return shbuf;
|
||||
}
|
||||
|
||||
// read a particular section's data
|
||||
void* read_section_data(int fd, ELF_EHDR* ehdr, ELF_SHDR* shdr) {
|
||||
void *buf = NULL;
|
||||
if (shdr->sh_type == SHT_NOBITS || shdr->sh_size == 0) {
|
||||
return buf;
|
||||
}
|
||||
if ((buf = calloc(shdr->sh_size, 1)) == NULL) {
|
||||
print_debug("can't allocate memory for reading section data\n");
|
||||
return NULL;
|
||||
}
|
||||
if (pread(fd, buf, shdr->sh_size, shdr->sh_offset) != shdr->sh_size) {
|
||||
free(buf);
|
||||
print_debug("section data read failed\n");
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
uintptr_t find_base_address(int fd, ELF_EHDR* ehdr) {
|
||||
uintptr_t baseaddr = (uintptr_t)-1;
|
||||
int cnt;
|
||||
ELF_PHDR *phbuf, *phdr;
|
||||
|
||||
// read program header table
|
||||
if ((phbuf = read_program_header_table(fd, ehdr)) == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
// the base address of a shared object is the lowest vaddr of
|
||||
// its loadable segments (PT_LOAD)
|
||||
for (phdr = phbuf, cnt = 0; cnt < ehdr->e_phnum; cnt++, phdr++) {
|
||||
if (phdr->p_type == PT_LOAD && phdr->p_vaddr < baseaddr) {
|
||||
baseaddr = phdr->p_vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
quit:
|
||||
if (phbuf) free(phbuf);
|
||||
return baseaddr;
|
||||
}
|
52
hotspot/agent/src/os/bsd/salibelf.h
Normal file
52
hotspot/agent/src/os/bsd/salibelf.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SALIBELF_H_
|
||||
#define _SALIBELF_H_
|
||||
|
||||
#include <elf.h>
|
||||
#include "elfmacros.h"
|
||||
#include "libproc_impl.h"
|
||||
|
||||
// read ELF file header.
|
||||
int read_elf_header(int fd, ELF_EHDR* ehdr);
|
||||
|
||||
// is given file descriptor corresponds to an ELF file?
|
||||
bool is_elf_file(int fd);
|
||||
|
||||
// read program header table of an ELF file. caller has to
|
||||
// free the result pointer after use. NULL on failure.
|
||||
ELF_PHDR* read_program_header_table(int fd, ELF_EHDR* hdr);
|
||||
|
||||
// read section header table of an ELF file. caller has to
|
||||
// free the result pointer after use. NULL on failure.
|
||||
ELF_SHDR* read_section_header_table(int fd, ELF_EHDR* hdr);
|
||||
|
||||
// read a particular section's data. caller has to free the
|
||||
// result pointer after use. NULL on failure.
|
||||
void* read_section_data(int fd, ELF_EHDR* ehdr, ELF_SHDR* shdr);
|
||||
|
||||
// find the base address at which the library wants to load itself
|
||||
uintptr_t find_base_address(int fd, ELF_EHDR* ehdr);
|
||||
#endif /* _SALIBELF_H_ */
|
249
hotspot/agent/src/os/bsd/symtab.c
Normal file
249
hotspot/agent/src/os/bsd/symtab.c
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <search.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <db.h>
|
||||
#include <fcntl.h>
|
||||
#include "symtab.h"
|
||||
#include "salibelf.h"
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
// functions for symbol lookups
|
||||
// ----------------------------------------------------
|
||||
|
||||
struct elf_section {
|
||||
ELF_SHDR *c_shdr;
|
||||
void *c_data;
|
||||
};
|
||||
|
||||
struct elf_symbol {
|
||||
char *name;
|
||||
uintptr_t offset;
|
||||
uintptr_t size;
|
||||
};
|
||||
|
||||
typedef struct symtab {
|
||||
char *strs;
|
||||
size_t num_symbols;
|
||||
struct elf_symbol *symbols;
|
||||
DB* hash_table;
|
||||
} symtab_t;
|
||||
|
||||
// read symbol table from given fd.
|
||||
struct symtab* build_symtab(int fd) {
|
||||
ELF_EHDR ehdr;
|
||||
struct symtab* symtab = NULL;
|
||||
|
||||
// Reading of elf header
|
||||
struct elf_section *scn_cache = NULL;
|
||||
int cnt = 0;
|
||||
ELF_SHDR* shbuf = NULL;
|
||||
ELF_SHDR* cursct = NULL;
|
||||
ELF_PHDR* phbuf = NULL;
|
||||
int symtab_found = 0;
|
||||
int dynsym_found = 0;
|
||||
uint32_t symsection = SHT_SYMTAB;
|
||||
|
||||
uintptr_t baseaddr = (uintptr_t)-1;
|
||||
|
||||
lseek(fd, (off_t)0L, SEEK_SET);
|
||||
if (! read_elf_header(fd, &ehdr)) {
|
||||
// not an elf
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read ELF header
|
||||
if ((shbuf = read_section_header_table(fd, &ehdr)) == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
baseaddr = find_base_address(fd, &ehdr);
|
||||
|
||||
scn_cache = calloc(ehdr.e_shnum, sizeof(*scn_cache));
|
||||
if (scn_cache == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) {
|
||||
scn_cache[cnt].c_shdr = cursct;
|
||||
if (cursct->sh_type == SHT_SYMTAB ||
|
||||
cursct->sh_type == SHT_STRTAB ||
|
||||
cursct->sh_type == SHT_DYNSYM) {
|
||||
if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
if (cursct->sh_type == SHT_SYMTAB)
|
||||
symtab_found++;
|
||||
|
||||
if (cursct->sh_type == SHT_DYNSYM)
|
||||
dynsym_found++;
|
||||
|
||||
cursct++;
|
||||
}
|
||||
|
||||
if (!symtab_found && dynsym_found)
|
||||
symsection = SHT_DYNSYM;
|
||||
|
||||
for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {
|
||||
ELF_SHDR *shdr = scn_cache[cnt].c_shdr;
|
||||
|
||||
if (shdr->sh_type == symsection) {
|
||||
ELF_SYM *syms;
|
||||
int j, n;
|
||||
size_t size;
|
||||
|
||||
// FIXME: there could be multiple data buffers associated with the
|
||||
// same ELF section. Here we can handle only one buffer. See man page
|
||||
// for elf_getdata on Solaris.
|
||||
|
||||
// guarantee(symtab == NULL, "multiple symtab");
|
||||
symtab = calloc(1, sizeof(*symtab));
|
||||
if (symtab == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
// the symbol table
|
||||
syms = (ELF_SYM *)scn_cache[cnt].c_data;
|
||||
|
||||
// number of symbols
|
||||
n = shdr->sh_size / shdr->sh_entsize;
|
||||
|
||||
// create hash table, we use berkeley db to
|
||||
// manipulate the hash table.
|
||||
symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL);
|
||||
// guarantee(symtab->hash_table, "unexpected failure: dbopen");
|
||||
if (symtab->hash_table == NULL)
|
||||
goto bad;
|
||||
|
||||
// shdr->sh_link points to the section that contains the actual strings
|
||||
// for symbol names. the st_name field in ELF_SYM is just the
|
||||
// string table index. we make a copy of the string table so the
|
||||
// strings will not be destroyed by elf_end.
|
||||
size = scn_cache[shdr->sh_link].c_shdr->sh_size;
|
||||
symtab->strs = malloc(size);
|
||||
if (symtab->strs == NULL)
|
||||
goto bad;
|
||||
memcpy(symtab->strs, scn_cache[shdr->sh_link].c_data, size);
|
||||
|
||||
// allocate memory for storing symbol offset and size;
|
||||
symtab->num_symbols = n;
|
||||
symtab->symbols = calloc(n , sizeof(*symtab->symbols));
|
||||
if (symtab->symbols == NULL)
|
||||
goto bad;
|
||||
|
||||
// copy symbols info our symtab and enter them info the hash table
|
||||
for (j = 0; j < n; j++, syms++) {
|
||||
DBT key, value;
|
||||
char *sym_name = symtab->strs + syms->st_name;
|
||||
|
||||
// skip non-object and non-function symbols
|
||||
int st_type = ELF_ST_TYPE(syms->st_info);
|
||||
if ( st_type != STT_FUNC && st_type != STT_OBJECT)
|
||||
continue;
|
||||
// skip empty strings and undefined symbols
|
||||
if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;
|
||||
|
||||
symtab->symbols[j].name = sym_name;
|
||||
symtab->symbols[j].offset = syms->st_value - baseaddr;
|
||||
symtab->symbols[j].size = syms->st_size;
|
||||
|
||||
key.data = sym_name;
|
||||
key.size = strlen(sym_name) + 1;
|
||||
value.data = &(symtab->symbols[j]);
|
||||
value.size = sizeof(void *);
|
||||
(*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
goto quit;
|
||||
|
||||
bad:
|
||||
destroy_symtab(symtab);
|
||||
symtab = NULL;
|
||||
|
||||
quit:
|
||||
if (shbuf) free(shbuf);
|
||||
if (phbuf) free(phbuf);
|
||||
if (scn_cache) {
|
||||
for (cnt = 0; cnt < ehdr.e_shnum; cnt++) {
|
||||
if (scn_cache[cnt].c_data != NULL) {
|
||||
free(scn_cache[cnt].c_data);
|
||||
}
|
||||
}
|
||||
free(scn_cache);
|
||||
}
|
||||
return symtab;
|
||||
}
|
||||
|
||||
void destroy_symtab(struct symtab* symtab) {
|
||||
if (!symtab) return;
|
||||
if (symtab->strs) free(symtab->strs);
|
||||
if (symtab->symbols) free(symtab->symbols);
|
||||
if (symtab->hash_table) {
|
||||
(*symtab->hash_table->close)(symtab->hash_table);
|
||||
}
|
||||
free(symtab);
|
||||
}
|
||||
|
||||
uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
|
||||
const char *sym_name, int *sym_size) {
|
||||
DBT key, value;
|
||||
int ret;
|
||||
|
||||
// library does not have symbol table
|
||||
if (!symtab || !symtab->hash_table)
|
||||
return 0;
|
||||
|
||||
key.data = (char*)(uintptr_t)sym_name;
|
||||
key.size = strlen(sym_name) + 1;
|
||||
ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0);
|
||||
if (ret == 0) {
|
||||
struct elf_symbol *sym = value.data;
|
||||
uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
|
||||
if (sym_size) *sym_size = sym->size;
|
||||
return rslt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
|
||||
uintptr_t* poffset) {
|
||||
int n = 0;
|
||||
if (!symtab) return NULL;
|
||||
for (; n < symtab->num_symbols; n++) {
|
||||
struct elf_symbol* sym = &(symtab->symbols[n]);
|
||||
if (sym->name != NULL &&
|
||||
offset >= sym->offset && offset < sym->offset + sym->size) {
|
||||
if (poffset) *poffset = (offset - sym->offset);
|
||||
return sym->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
50
hotspot/agent/src/os/bsd/symtab.h
Normal file
50
hotspot/agent/src/os/bsd/symtab.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SYMTAB_H_
|
||||
#define _SYMTAB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// interface to manage ELF symbol tables
|
||||
|
||||
struct symtab;
|
||||
|
||||
// build symbol table for a given ELF file descriptor
|
||||
struct symtab* build_symtab(int fd);
|
||||
|
||||
// destroy the symbol table
|
||||
void destroy_symtab(struct symtab* symtab);
|
||||
|
||||
// search for symbol in the given symbol table. Adds offset
|
||||
// to the base uintptr_t supplied. Returns NULL if not found.
|
||||
uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
|
||||
const char *sym_name, int *sym_size);
|
||||
|
||||
// look for nearest symbol for a given offset (not address - base
|
||||
// subtraction done by caller
|
||||
const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
|
||||
uintptr_t* poffset);
|
||||
|
||||
#endif /*_SYMTAB_H_*/
|
59
hotspot/agent/src/os/bsd/test.c
Normal file
59
hotspot/agent/src/os/bsd/test.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "libproc.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct ps_prochandle* ph;
|
||||
|
||||
init_libproc(true);
|
||||
switch (argc) {
|
||||
case 2: {
|
||||
// process
|
||||
ph = Pgrab(atoi(argv[1]));
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
// core
|
||||
ph = Pgrab_core(argv[1], argv[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "usage %s <pid> or %s <exec file> <core file>\n", argv[0], argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ph) {
|
||||
Prelease(ph);
|
||||
return 0;
|
||||
} else {
|
||||
printf("can't connect to debuggee\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -40,7 +40,7 @@ OBJS = $(SOURCES:.c=.o)
|
|||
|
||||
LIBS = -lthread_db
|
||||
|
||||
CFLAGS = -c -fPIC -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES)
|
||||
CFLAGS = -c -fPIC -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) -D_FILE_OFFSET_BITS=64
|
||||
|
||||
LIBSA = $(ARCH)/libsaproc.so
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -50,10 +50,6 @@ int pathmap_open(const char* name) {
|
|||
char alt_path[PATH_MAX + 1];
|
||||
|
||||
init_alt_root();
|
||||
fd = open(name, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (alt_root_len > 0) {
|
||||
strcpy(alt_path, alt_root);
|
||||
|
@ -73,6 +69,11 @@ int pathmap_open(const char* name) {
|
|||
return fd;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fd = open(name, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
|
||||
|
||||
all:
|
||||
cd dbx; $(MAKE) all
|
||||
cd proc; $(MAKE) all
|
||||
|
||||
clean:
|
||||
cd dbx; $(MAKE) clean
|
||||
cd proc; $(MAKE) clean
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
# Targets are:
|
||||
# 32bit: Build the 32 bit version in ./32bit
|
||||
# 64bit: Build the 64 bit version in ./64bit
|
||||
# helloWorld: Build the helloWorld test program
|
||||
# all: Build all of the above. This is the default.
|
||||
#
|
||||
# NOTE: This makefile uses IOBuf.cpp, IOBuf.hpp, Buffer.cpp, and
|
||||
# Buffer.hpp from the src/os/win32/agent directory.
|
||||
|
||||
.PHONY: 32bit 64bit
|
||||
|
||||
ARCH_ORIG = $(shell uname -p)
|
||||
|
||||
# C++ := /java/devtools/$(ARCH_ORIG)/SUNWspro/SC6.1/bin/CC
|
||||
|
||||
C++ := CC
|
||||
RM := /usr/bin/rm
|
||||
MKDIRS := /usr/bin/mkdir -p
|
||||
|
||||
|
||||
WIN32_DIR := ../../win32
|
||||
ARCH := $(subst i386,i486,$(ARCH_ORIG))
|
||||
# INCLUDES := -I/net/sparcworks.eng/export/set/sparcworks5/dbx_62_intg/dev/src/dbx -I$(WIN32_DIR)
|
||||
INCLUDES := -I. -I$(WIN32_DIR)
|
||||
CFLAGS_32bit := -xarch=v8
|
||||
CFLAGS_64bit := -xarch=v9
|
||||
CFLAGS := -PIC -xO3 $(INCLUDES)
|
||||
LIBS := -lsocket -lnsl -lrtld_db
|
||||
LDFLAGS := -G
|
||||
|
||||
ifneq "$(ARCH)" "i486"
|
||||
CFLAGS += $(CFLAGS_$(VERSION))
|
||||
LDFLAGS += $(CFLAGS_$(VERSION))
|
||||
endif
|
||||
|
||||
# We use IOBuf.hpp, IOBuf.cpp, Buffer.hpp, and Buffer.cpp from the win32 dir.
|
||||
vpath %.cpp .:$(WIN32_DIR)
|
||||
vpath %.hpp .:$(WIN32_DIR)
|
||||
|
||||
OBJS = $(VERSION)/svc_agent_dbx.o $(VERSION)/IOBuf.o $(VERSION)/Buffer.o
|
||||
|
||||
|
||||
|
||||
# The default is to make both 32 bit and 64 bit versions.
|
||||
all:: 32bit 64bit
|
||||
|
||||
32bit 64bit::
|
||||
$(MKDIRS) $@
|
||||
$(MAKE) $@/libsvc_agent_dbx.so helloWorld VERSION=$@
|
||||
|
||||
$(VERSION)/IOBuf.o: IOBuf.hpp
|
||||
$(VERSION)/Buffer.o: Buffer.hpp
|
||||
$(VERSION)/svc_agent_dbx.o: svc_agent_dbx.hpp
|
||||
|
||||
$(VERSION)/%.o: %.cpp
|
||||
$(C++) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(VERSION)/libsvc_agent_dbx.so:: $(OBJS)
|
||||
$(C++) $(LDFLAGS) -o $(VERSION)/libsvc_agent_dbx.so $(OBJS) $(LIBS)
|
||||
|
||||
# Would be nice to move this into a shared directory
|
||||
helloWorld:: helloWorld.cpp
|
||||
$(C++) -g $< -o $@
|
||||
|
||||
clean::
|
||||
$(RM) -rf 32bit 64bit *.o helloWorld
|
|
@ -1,9 +0,0 @@
|
|||
shell_impl.h
|
||||
proc_service_2.h
|
||||
|
||||
The above files are captured from the dbx build environment.
|
||||
Rather then use a -I that points to stuff in .eng domain that
|
||||
may not be accessible in other domains these files are just
|
||||
copied here so local builds in other domains will work.
|
||||
These files rarely change so the fact that we might have to
|
||||
strobe in new ones on rare occasions is no big deal.
|
|
@ -1,82 +0,0 @@
|
|||
This import module uses a largely text-based protocol, except for
|
||||
certain bulk data transfer operations. All text is in single-byte
|
||||
US-ASCII.
|
||||
|
||||
Commands understood:
|
||||
|
||||
address_size ::= <int result>
|
||||
|
||||
Returns 32 if attached to 32-bit process, 64 if 64-bit.
|
||||
|
||||
peek_fail_fast <bool arg> ::=
|
||||
|
||||
Indicates whether "peek" requests should "fail fast"; that is, if
|
||||
any of the addresses in the requested range are unmapped, report
|
||||
the entire range as unmapped. This is substantially faster than
|
||||
the alternative, which is to read the entire range byte-by-byte.
|
||||
However, it should only be used when it is guaranteed by the
|
||||
client application that peeks come from at most one page. The
|
||||
default is that peek_fast_fail is not enabled.
|
||||
|
||||
peek <address addr> <unsigned int numBytes> ::=
|
||||
B<binary char success>
|
||||
[<binary unsigned int len> <binary char isMapped> [<binary char data>]...]...
|
||||
|
||||
NOTE that the binary portion of this message is prefixed by the
|
||||
uppercase US-ASCII letter 'B', allowing easier synchronization by
|
||||
clients. There is no data between the 'B' and the rest of the
|
||||
message.
|
||||
|
||||
May only be called once attached. Reads the address space of the
|
||||
target process starting at the given address (see below for format
|
||||
specifications) and extending the given number of bytes. Whether
|
||||
the read succeeded is indicated by a single byte containing a 1 or
|
||||
0 (success or failure). If successful, the return result is given
|
||||
in a sequence of ranges. _len_, the length of each range, is
|
||||
indicated by a 32-bit unsigned integer transmitted with big-endian
|
||||
byte ordering (i.e., most significant byte first). _isMapped_
|
||||
indicates whether the range is mapped or unmapped in the target
|
||||
process's address space, and will contain the value 1 or 0 for
|
||||
mapped or unmapped, respectively. If the range is mapped,
|
||||
_isMapped_ is followed by _data_, containing the raw binary data
|
||||
for the range. The sum of all ranges' lengths is guaranteed to be
|
||||
equivalent to the number of bytes requested.
|
||||
|
||||
poke <address addr> <int numBytes> B[<binary char data>]... ::= <bool result>
|
||||
|
||||
NOTE that the binary portion of this message is prefixed by the
|
||||
uppercase US-ASCII letter 'B', allowing easier synchronization by
|
||||
clients. There is no data between the 'B' and the rest of the
|
||||
message.
|
||||
|
||||
Writes the given data to the target process starting at the given
|
||||
address. Returns 1 on success, 0 on failure (i.e., one or more of
|
||||
target addresses were unmapped).
|
||||
|
||||
mapped <address addr> <int numBytes> ::= <bool result>
|
||||
|
||||
Returns 1 if entire address range [address...address + int arg) is
|
||||
mapped in target process's address space, 0 if not
|
||||
|
||||
lookup <symbol objName> <symbol sym> ::= <address addr>
|
||||
|
||||
First symbol is object name; second is symbol to be looked up.
|
||||
Looks up symbol in target process's symbol table and returns
|
||||
address. Returns NULL (0x0) if symbol is not found.
|
||||
|
||||
thr_gregs <int tid> ::= <int numAddresses> <address...>
|
||||
|
||||
Fetch the "general" (integer) register set for the given thread.
|
||||
Returned as a series of hexidecimal values. NOTE: the meaning of
|
||||
the return value is architecture-dependent. In general it is the
|
||||
contents of the prgregset_t.
|
||||
|
||||
exit ::=
|
||||
|
||||
Exits the serviceability agent dbx module, returning control to
|
||||
the dbx prompt.
|
||||
|
||||
// Data formats and example values:
|
||||
<address> ::= 0x12345678[9ABCDEF0] /* up to 64-bit hex value */
|
||||
<unsigned int> ::= 5 /* up to 32-bit integer number; no leading sign */
|
||||
<bool> ::= 1 /* ASCII '0' or '1' */
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
extern "C" {
|
||||
const char* helloWorldString = "Hello, world!";
|
||||
// Do not change these values without changing TestDebugger.java as well
|
||||
// FIXME: should make these jbyte, jshort, etc...
|
||||
volatile int8_t testByte = 132;
|
||||
volatile int16_t testShort = 27890;
|
||||
volatile int32_t testInt = 1020304050;
|
||||
volatile int64_t testLong = 102030405060708090LL;
|
||||
volatile float testFloat = 35.4F;
|
||||
volatile double testDouble = 1.23456789;
|
||||
|
||||
volatile int helloWorldTrigger = 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int, char**) {
|
||||
while (1) {
|
||||
while (helloWorldTrigger == 0) {
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s\n", helloWorldString);
|
||||
fprintf(stderr, "testByte=%d\n", testByte);
|
||||
fprintf(stderr, "testShort=%d\n", testShort);
|
||||
fprintf(stderr, "testInt=%d\n", testInt);
|
||||
fprintf(stderr, "testLong=%d\n", testLong);
|
||||
fprintf(stderr, "testFloat=%d\n", testFloat);
|
||||
fprintf(stderr, "testDouble=%d\n", testDouble);
|
||||
|
||||
while (helloWorldTrigger != 0) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PROC_SERVICE_2_H
|
||||
#define _PROC_SERVICE_2_H
|
||||
|
||||
/*
|
||||
* Types, function definitions for the provider of services beyond
|
||||
* proc_service. This interface will be used by import modules like
|
||||
* BAT/prex, NEO debugger etc.
|
||||
*/
|
||||
|
||||
/*
|
||||
CCR info
|
||||
|
||||
Version history:
|
||||
|
||||
1.0 - Initial CCR release
|
||||
|
||||
1.1 - Changes for GLUE/neo.
|
||||
New entry points ps_svnt_generic() and ps_svc_generic()
|
||||
- New entry point ps_getpid()
|
||||
|
||||
Release information for automatic CCR updates:
|
||||
BEGIN RELEASE NOTES: (signifies what gets put into CCR release notes)
|
||||
1.2 - Changes to support Solaris 2.7
|
||||
|
||||
END RELEASE NOTES: (signifies what gets put into CCR release notes)
|
||||
|
||||
Following is used for CCR version number:
|
||||
|
||||
#define CCR_PROC_SERVICE_2_VERSION 1.2
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <proc_service.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ps_loadobj {
|
||||
int objfd; /* fd of the load object or executable
|
||||
* -1 implies its not available.
|
||||
* This file decriptor is live only during the
|
||||
* particular call to ps_iter_f(). If you
|
||||
* need it beyond that you need to dup() it.
|
||||
*/
|
||||
psaddr_t
|
||||
text_base; /* address where text of loadobj was mapped */
|
||||
psaddr_t
|
||||
data_base; /* address where data of loadobj was mapped */
|
||||
const char *objname; /* loadobj name */
|
||||
};
|
||||
|
||||
typedef int ps_iter_f(const struct ps_prochandle *, const struct ps_loadobj *,
|
||||
void *cd);
|
||||
|
||||
/*
|
||||
* Returns the ps_prochandle for the current process under focus. Returns
|
||||
* NULL if there is none.
|
||||
*/
|
||||
|
||||
const struct ps_prochandle *
|
||||
ps_get_prochandle(void);
|
||||
|
||||
/*
|
||||
* Returns the ps_prochandle for the current process(allows core files to
|
||||
* be specified) under focus. Returns NULL if there is none.
|
||||
*/
|
||||
const struct ps_prochandle *
|
||||
ps_get_prochandle2(int cores_too);
|
||||
|
||||
/*
|
||||
* Returns the pid of the process referred to by the ps_prochandle.
|
||||
*
|
||||
* 0 is returned in case the ps_prochandle is not valid or refers to dead
|
||||
* process.
|
||||
*
|
||||
*/
|
||||
pid_t
|
||||
ps_getpid(const struct ps_prochandle *);
|
||||
|
||||
/*
|
||||
* Iteration function that iterates over all load objects *and the
|
||||
* executable*
|
||||
*
|
||||
* If the callback routine returns:
|
||||
* 0 - continue processing link objects
|
||||
* non zero - stop calling the callback function
|
||||
*
|
||||
*/
|
||||
|
||||
ps_err_e
|
||||
ps_loadobj_iter(const struct ps_prochandle *, ps_iter_f *, void *clnt_data);
|
||||
|
||||
/*
|
||||
* Address => function name mapping
|
||||
*
|
||||
* Given an address, returns a pointer to the function's
|
||||
* linker name (null terminated).
|
||||
*/
|
||||
|
||||
ps_err_e
|
||||
ps_find_fun_name(const struct ps_prochandle *, psaddr_t addr,
|
||||
const char **name);
|
||||
|
||||
/*
|
||||
* Interface to LD_PRELOAD. LD_PRELOAD given library across the
|
||||
* program 'exec'.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Append/Prepend the 'lib' (has to be library name as understood by LD_PRELOAD)
|
||||
* to the LD_PRELOAD variable setting to be used by the debugee
|
||||
* Returns a cookie (in id).
|
||||
*/
|
||||
ps_err_e
|
||||
ps_ld_preload_append(const char *lib, int *id);
|
||||
ps_err_e
|
||||
ps_ld_preload_prepend(const char *lib, int *id);
|
||||
|
||||
/*
|
||||
* Remove the library associated with 'id' from the LD_PRELOAD setting.
|
||||
*
|
||||
*/
|
||||
ps_err_e
|
||||
ps_ld_preload_remove(int id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following are C++ only interfaces
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
/*
|
||||
* classes ServiceDbx and ServantDbx and defined in "gp_dbx_svc.h" which is
|
||||
* accessed via CCR
|
||||
*/
|
||||
extern class ServantDbx *ps_svnt_generic();
|
||||
extern class ServiceDbx *ps_svc_generic();
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _PROC_SERVICE_2_H */
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHELL_IMP_H
|
||||
#define SHELL_IMP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
CCR info
|
||||
|
||||
Vesrion history:
|
||||
|
||||
1.0 - Initial CCR release
|
||||
|
||||
Release information for automatic CCR updates:
|
||||
|
||||
BEGIN RELEASE NOTES: (signifies what gets put into CCR release notes)
|
||||
1.1
|
||||
- Entry points for va_list style msgs; new shell_imp_vmsg()
|
||||
and shell_imp_verrmsg()
|
||||
- shell_imp_env_checker() is now shell_imp_var_checker().
|
||||
Also the var_checker callback gets passed interp.
|
||||
1.2 - interposition framework (used by jdbx)
|
||||
- access to input FILE pointer.
|
||||
|
||||
END RELEASE NOTES: (signifies what gets put into CCR release notes)
|
||||
|
||||
Following is used as a CCR version number:
|
||||
#define CCR_SHELL_IMP_VERSION 1.1
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define SHELL_IMP_MAJOR 1
|
||||
#define SHELL_IMP_MINOR 2
|
||||
#define SHELL_IMP_FLAG_GLOB 0x1
|
||||
#define SHELL_IMP_FLAG_ARGQ 0x2
|
||||
|
||||
typedef void *shell_imp_interp_t;
|
||||
typedef void *shell_imp_command_t;
|
||||
typedef int shell_imp_fun_t(shell_imp_interp_t, int, char **, void *);
|
||||
|
||||
int
|
||||
shell_imp_init(
|
||||
int, /* major version number */
|
||||
int, /* minor version number */
|
||||
shell_imp_interp_t, /* interpreter */
|
||||
int, /* argc */
|
||||
char *[] /* argv */
|
||||
);
|
||||
|
||||
int
|
||||
shell_imp_fini(shell_imp_interp_t);
|
||||
|
||||
shell_imp_command_t
|
||||
shell_imp_define_command(char *, /* command name e.g. "tnf" */
|
||||
shell_imp_fun_t *, /* callback function */
|
||||
int, /* SHELL_IMP_FLAG_* bit vector */
|
||||
void *, /* client_data Passed as last arg to
|
||||
/* callback function */
|
||||
char * /* help message, e.g. */
|
||||
/* "enable the specified tnf probes" */
|
||||
);
|
||||
|
||||
int
|
||||
shell_imp_undefine_command(shell_imp_command_t);
|
||||
|
||||
int
|
||||
shell_imp_var_checker(shell_imp_interp_t,
|
||||
const char *, /* var name */
|
||||
int (*)(shell_imp_interp_t, const char*) /* env checker */
|
||||
);
|
||||
|
||||
int
|
||||
shell_imp_execute(shell_imp_interp_t, const char *);
|
||||
|
||||
const char *
|
||||
shell_imp_get_var(shell_imp_interp_t, const char *);
|
||||
|
||||
void
|
||||
shell_imp_msg(shell_imp_interp_t, const char *, ...);
|
||||
|
||||
void
|
||||
shell_imp_errmsg(shell_imp_interp_t, const char *, ...);
|
||||
|
||||
void
|
||||
shell_imp_vmsg(shell_imp_interp_t, const char *, va_list);
|
||||
|
||||
void
|
||||
shell_imp_verrmsg(shell_imp_interp_t, const char *, va_list);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Stuff added for 1.2
|
||||
*/
|
||||
|
||||
struct shell_imp_interposition_info_t {
|
||||
shell_imp_fun_t *
|
||||
new_func;
|
||||
void * new_client_data;
|
||||
shell_imp_fun_t *
|
||||
original_func;
|
||||
void * original_client_data;
|
||||
int original_flags;
|
||||
};
|
||||
|
||||
typedef int shell_imp_dispatcher_t(shell_imp_interp_t, int, char **,
|
||||
shell_imp_interposition_info_t *);
|
||||
|
||||
shell_imp_command_t
|
||||
shell_imp_interpose(char *name,
|
||||
shell_imp_fun_t *new_func,
|
||||
int flags,
|
||||
void *client_data,
|
||||
char * description,
|
||||
shell_imp_dispatcher_t *);
|
||||
|
||||
int shell_imp_uninterpose(shell_imp_command_t);
|
||||
|
||||
int
|
||||
shell_imp_dispatch_interposition(shell_imp_interp_t,
|
||||
shell_imp_interposition_info_t *,
|
||||
int argc, char *argv[]);
|
||||
|
||||
int
|
||||
shell_imp_dispatch_original(shell_imp_interp_t,
|
||||
shell_imp_interposition_info_t *,
|
||||
int argc, char *argv[]);
|
||||
|
||||
FILE *
|
||||
shell_imp_cur_input(shell_imp_interp_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shell_imp.h"
|
||||
#include "IOBuf.hpp"
|
||||
#include <sys/time.h>
|
||||
#include <thread_db.h>
|
||||
|
||||
typedef td_err_e td_init_fn_t();
|
||||
typedef td_err_e td_ta_new_fn_t(struct ps_prochandle *, td_thragent_t **);
|
||||
typedef td_err_e td_ta_delete_fn_t(td_thragent_t *);
|
||||
typedef td_err_e td_ta_map_id2thr_fn_t(const td_thragent_t *, thread_t, td_thrhandle_t *);
|
||||
typedef td_err_e td_thr_getgregs_fn_t(const td_thrhandle_t *, prgregset_t);
|
||||
|
||||
class ServiceabilityAgentDbxModule {
|
||||
public:
|
||||
ServiceabilityAgentDbxModule(int major, int minor,
|
||||
shell_imp_interp_t interp, int argc, char *argv[]);
|
||||
~ServiceabilityAgentDbxModule();
|
||||
|
||||
bool install();
|
||||
bool uninstall();
|
||||
|
||||
/* This is invoked through the dbx command interpreter. It listens
|
||||
on a socket for commands and does not return until it receives an
|
||||
"exit" command. At that point control is returned to dbx's main
|
||||
loop, at which point if the user sends an exit command to dbx's
|
||||
shell the dbx process will exit. Returns true if completed
|
||||
successfully, false if an error occurred while running (for
|
||||
example, unable to bind listening socket). */
|
||||
bool run();
|
||||
|
||||
private:
|
||||
|
||||
// This must be shared between the Java and C layers
|
||||
static const int PORT = 21928;
|
||||
|
||||
// Command handlers
|
||||
bool handleAddressSize(char* data);
|
||||
bool handlePeekFailFast(char* data);
|
||||
bool handlePeek(char* data);
|
||||
bool handlePoke(char* data);
|
||||
bool handleMapped(char* data);
|
||||
bool handleLookup(char* data);
|
||||
bool handleThrGRegs(char* data);
|
||||
|
||||
// Input routines
|
||||
|
||||
// May mutate addr argument even if result is false
|
||||
bool scanAddress(char** data, psaddr_t* addr);
|
||||
// May mutate num argument even if result is false
|
||||
bool scanUnsignedInt(char** data, unsigned int* num);
|
||||
// Returns NULL if error occurred while scanning. Otherwise, returns
|
||||
// newly-allocated character array which must be freed with delete[].
|
||||
char* scanSymbol(char** data);
|
||||
// Helper routine: converts ASCII to 4-bit integer. Returns true if
|
||||
// character is in range, false otherwise.
|
||||
bool charToNibble(char ascii, int* value);
|
||||
|
||||
// Output routines
|
||||
|
||||
// Writes an int with no leading or trailing spaces
|
||||
bool writeInt(int val, int fd);
|
||||
// Writes an address in hex format with no leading or trailing
|
||||
// spaces
|
||||
bool writeAddress(psaddr_t addr, int fd);
|
||||
// Writes a register in hex format with no leading or trailing
|
||||
// spaces (addresses and registers might be of different size)
|
||||
bool writeRegister(prgreg_t reg, int fd);
|
||||
// Writes a space to given file descriptor
|
||||
bool writeSpace(int fd);
|
||||
// Writes carriage return to given file descriptor
|
||||
bool writeCR(int fd);
|
||||
// Writes a bool as [0|1]
|
||||
bool writeBoolAsInt(bool val, int fd);
|
||||
// Helper routine: converts low 4 bits to ASCII [0..9][A..F]
|
||||
char nibbleToChar(unsigned char nibble);
|
||||
|
||||
// Base routine called by most of the above
|
||||
bool writeString(const char* str, int fd);
|
||||
|
||||
// Writes a binary character
|
||||
bool writeBinChar(char val, int fd);
|
||||
// Writes a binary unsigned int in network (big-endian) byte order
|
||||
bool writeBinUnsignedInt(unsigned int val, int fd);
|
||||
// Writes a binary buffer
|
||||
bool writeBinBuf(char* buf, int size, int fd);
|
||||
|
||||
// Routine to flush the socket
|
||||
bool flush(int client_socket);
|
||||
|
||||
void cleanup(int client_socket);
|
||||
|
||||
// The shell interpreter on which we can invoke commands (?)
|
||||
shell_imp_interp_t _interp;
|
||||
|
||||
// The "command line" arguments passed to us by dbx (?)
|
||||
int _argc;
|
||||
char **_argv;
|
||||
|
||||
// The installed command in the dbx shell
|
||||
shell_imp_command_t _command;
|
||||
|
||||
// Access to libthread_db (dlsym'ed to be able to pick up the
|
||||
// version loaded by dbx)
|
||||
td_init_fn_t* td_init_fn;
|
||||
td_ta_new_fn_t* td_ta_new_fn;
|
||||
td_ta_delete_fn_t* td_ta_delete_fn;
|
||||
td_ta_map_id2thr_fn_t* td_ta_map_id2thr_fn;
|
||||
td_thr_getgregs_fn_t* td_thr_getgregs_fn;
|
||||
|
||||
// Our "thread agent" -- access to libthread_db
|
||||
td_thragent_t* _tdb_agent;
|
||||
|
||||
// Path to libthread.so in target process; free with delete[]
|
||||
char* libThreadName;
|
||||
|
||||
// Handle to dlopen'ed libthread_db.so
|
||||
void* libThreadDB;
|
||||
|
||||
// Helper callback for finding libthread_db.so
|
||||
friend int findLibThreadCB(const rd_loadobj_t* lo, void* data);
|
||||
|
||||
// Support for reading C strings out of the target process (so we
|
||||
// can find the correct libthread_db). Returns newly-allocated char*
|
||||
// which must be freed with delete[], or null if the read failed.
|
||||
char* readCStringFromProcess(psaddr_t addr);
|
||||
|
||||
IOBuf myComm;
|
||||
|
||||
// Output buffer support (used by writeString, writeChar, flush)
|
||||
char* output_buffer;
|
||||
int output_buffer_size;
|
||||
int output_buffer_pos;
|
||||
|
||||
// "Fail fast" flag
|
||||
bool peek_fail_fast;
|
||||
|
||||
// Commands
|
||||
static const char* CMD_ADDRESS_SIZE;
|
||||
static const char* CMD_PEEK_FAIL_FAST;
|
||||
static const char* CMD_PEEK;
|
||||
static const char* CMD_POKE;
|
||||
static const char* CMD_MAPPED;
|
||||
static const char* CMD_LOOKUP;
|
||||
static const char* CMD_THR_GREGS;
|
||||
static const char* CMD_EXIT;
|
||||
};
|
||||
|
||||
// For profiling. Times reported are in milliseconds.
|
||||
class Timer {
|
||||
public:
|
||||
Timer();
|
||||
~Timer();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
long total();
|
||||
long average();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
struct timeval startTime;
|
||||
long long totalMicroseconds; // stored internally in microseconds
|
||||
int counter;
|
||||
long long timevalDiff(struct timeval* startTime, struct timeval* endTime);
|
||||
};
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BASIC_LIST_
|
||||
#define _BASIC_LIST_
|
||||
|
||||
#include <vector>
|
||||
|
||||
template<class T>
|
||||
class BasicList {
|
||||
protected:
|
||||
typedef std::vector<T> InternalListType;
|
||||
InternalListType internalList;
|
||||
|
||||
public:
|
||||
BasicList() {
|
||||
}
|
||||
virtual ~BasicList() {
|
||||
}
|
||||
|
||||
void add(T arg) {
|
||||
internalList.push_back(arg);
|
||||
}
|
||||
|
||||
bool remove(T arg) {
|
||||
for (InternalListType::iterator iter = internalList.begin();
|
||||
iter != internalList.end(); iter++) {
|
||||
if (*iter == arg) {
|
||||
internalList.erase(iter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int size() {
|
||||
return internalList.size();
|
||||
}
|
||||
|
||||
T get(int index) {
|
||||
return internalList[index];
|
||||
}
|
||||
};
|
||||
|
||||
#endif // #defined _BASIC_LIST_
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Buffer.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
Buffer::Buffer(int bufSize) {
|
||||
buf = new char[bufSize];
|
||||
sz = bufSize;
|
||||
fill = 0;
|
||||
drain = 0;
|
||||
}
|
||||
|
||||
Buffer::~Buffer() {
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
char*
|
||||
Buffer::fillPos() {
|
||||
return buf + fill;
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::remaining() {
|
||||
return sz - fill;
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::size() {
|
||||
return sz;
|
||||
}
|
||||
|
||||
bool
|
||||
Buffer::incrFillPos(int amt) {
|
||||
if (fill + amt >= sz) {
|
||||
return false;
|
||||
}
|
||||
fill += amt;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::readByte() {
|
||||
if (drain < fill) {
|
||||
return buf[drain++] & 0xFF;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::readBytes(char* data, int len) {
|
||||
int numRead = 0;
|
||||
while (numRead < len) {
|
||||
int c = readByte();
|
||||
if (c < 0) break;
|
||||
data[numRead++] = (char) c;
|
||||
}
|
||||
return numRead;
|
||||
}
|
||||
|
||||
char*
|
||||
Buffer::drainPos() {
|
||||
return buf + drain;
|
||||
}
|
||||
|
||||
int
|
||||
Buffer::drainRemaining() {
|
||||
return fill - drain;
|
||||
}
|
||||
|
||||
bool
|
||||
Buffer::incrDrainPos(int amt) {
|
||||
if (drainRemaining() < amt) {
|
||||
return false;
|
||||
}
|
||||
drain += amt;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Buffer::compact() {
|
||||
// Copy down data
|
||||
memmove(buf, buf + drain, fill - drain);
|
||||
// Adjust positions
|
||||
fill -= drain;
|
||||
drain = 0;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BUFFER_
|
||||
#define _BUFFER_
|
||||
|
||||
// A Buffer is the backing store for the IOBuf abstraction and
|
||||
// supports producer-consumer filling and draining.
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
Buffer(int bufSize);
|
||||
~Buffer();
|
||||
|
||||
char* fillPos(); // Position of the place where buffer should be filled
|
||||
int remaining(); // Number of bytes that can be placed starting at fillPos
|
||||
int size(); // Size of the buffer
|
||||
// Move up fill position by amount (decreases remaining()); returns
|
||||
// false if not enough space
|
||||
bool incrFillPos(int amt);
|
||||
|
||||
// Read single byte (0..255); returns -1 if no data available.
|
||||
int readByte();
|
||||
// Read multiple bytes, non-blocking (this buffer does not define a
|
||||
// fill mechanism), into provided buffer. Returns number of bytes read.
|
||||
int readBytes(char* buf, int len);
|
||||
|
||||
// Access to drain position. Be very careful using this.
|
||||
char* drainPos();
|
||||
int drainRemaining();
|
||||
bool incrDrainPos(int amt);
|
||||
|
||||
// Compact buffer, removing already-consumed input. This must be
|
||||
// called periodically to yield the illusion of an infinite buffer.
|
||||
void compact();
|
||||
|
||||
private:
|
||||
Buffer(const Buffer&);
|
||||
Buffer& operator=(const Buffer&);
|
||||
|
||||
char* buf;
|
||||
int sz;
|
||||
int fill;
|
||||
int drain;
|
||||
};
|
||||
|
||||
#endif // #defined _BUFFER_
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "dispatcher.hpp"
|
||||
|
||||
const char* CMD_ASCII = "ascii";
|
||||
const char* CMD_UNICODE = "unicode";
|
||||
const char* CMD_PROCLIST = "proclist";
|
||||
const char* CMD_ATTACH = "attach";
|
||||
const char* CMD_DETACH = "detach";
|
||||
const char* CMD_LIBINFO = "libinfo";
|
||||
const char* CMD_PEEK = "peek";
|
||||
const char* CMD_POKE = "poke";
|
||||
const char* CMD_THREADLIST = "threadlist";
|
||||
const char* CMD_DUPHANDLE = "duphandle";
|
||||
const char* CMD_CLOSEHANDLE = "closehandle";
|
||||
const char* CMD_GETCONTEXT = "getcontext";
|
||||
const char* CMD_SETCONTEXT = "setcontext";
|
||||
const char* CMD_SELECTORENTRY = "selectorentry";
|
||||
const char* CMD_SUSPEND = "suspend";
|
||||
const char* CMD_RESUME = "resume";
|
||||
const char* CMD_POLLEVENT = "pollevent";
|
||||
const char* CMD_CONTINUEEVENT = "continueevent";
|
||||
const char* CMD_EXIT = "exit";
|
||||
|
||||
// Uncomment the #define below to get messages on stderr
|
||||
// #define DEBUGGING
|
||||
|
||||
void
|
||||
Dispatcher::dispatch(char* cmd, Handler* handler) {
|
||||
if (!strncmp(cmd, CMD_ASCII, strlen(CMD_ASCII))) {
|
||||
handler->ascii(cmd + strlen(CMD_ASCII));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_UNICODE, strlen(CMD_UNICODE))) {
|
||||
handler->unicode(cmd + strlen(CMD_UNICODE));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_PROCLIST, strlen(CMD_PROCLIST))) {
|
||||
handler->procList(cmd + strlen(CMD_PROCLIST));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_ATTACH, strlen(CMD_ATTACH))) {
|
||||
handler->attach(cmd + strlen(CMD_ATTACH));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_DETACH, strlen(CMD_DETACH))) {
|
||||
handler->detach(cmd + strlen(CMD_DETACH));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_LIBINFO, strlen(CMD_LIBINFO))) {
|
||||
handler->libInfo(cmd + strlen(CMD_LIBINFO));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_PEEK, strlen(CMD_PEEK))) {
|
||||
handler->peek(cmd + strlen(CMD_PEEK));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_POKE, strlen(CMD_POKE))) {
|
||||
handler->poke(cmd + strlen(CMD_POKE));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_THREADLIST, strlen(CMD_THREADLIST))) {
|
||||
handler->threadList(cmd + strlen(CMD_THREADLIST));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_DUPHANDLE, strlen(CMD_DUPHANDLE))) {
|
||||
handler->dupHandle(cmd + strlen(CMD_DUPHANDLE));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_CLOSEHANDLE, strlen(CMD_CLOSEHANDLE))) {
|
||||
handler->closeHandle(cmd + strlen(CMD_CLOSEHANDLE));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_GETCONTEXT, strlen(CMD_GETCONTEXT))) {
|
||||
handler->getContext(cmd + strlen(CMD_GETCONTEXT));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_SETCONTEXT, strlen(CMD_SETCONTEXT))) {
|
||||
handler->setContext(cmd + strlen(CMD_SETCONTEXT));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_SELECTORENTRY, strlen(CMD_SELECTORENTRY))) {
|
||||
handler->selectorEntry(cmd + strlen(CMD_SELECTORENTRY));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_SUSPEND, strlen(CMD_SUSPEND))) {
|
||||
handler->suspend(cmd + strlen(CMD_SUSPEND));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_RESUME, strlen(CMD_RESUME))) {
|
||||
handler->resume(cmd + strlen(CMD_RESUME));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_POLLEVENT, strlen(CMD_POLLEVENT))) {
|
||||
handler->pollEvent(cmd + strlen(CMD_POLLEVENT));
|
||||
|
||||
} else if (!strncmp(cmd, CMD_CONTINUEEVENT, strlen(CMD_CONTINUEEVENT))) {
|
||||
handler->continueEvent(cmd + strlen(CMD_CONTINUEEVENT));
|
||||
|
||||
} else if (!strcmp(cmd, CMD_EXIT)) {
|
||||
handler->exit(cmd + strlen(CMD_EXIT));
|
||||
}
|
||||
|
||||
#ifdef DEBUGGING
|
||||
else fprintf(stderr, "Ignoring illegal command \"%s\"\n", cmd);
|
||||
#endif
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DISPATCHER_
|
||||
#define _DISPATCHER_
|
||||
|
||||
#include "Handler.hpp"
|
||||
|
||||
/** This class understands the commands supported by the system and
|
||||
calls the appropriate handler routines. */
|
||||
|
||||
class Dispatcher {
|
||||
public:
|
||||
static void dispatch(char* cmd, Handler* handler);
|
||||
};
|
||||
|
||||
#endif // #defined _DISPATCHER_
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HANDLER_
|
||||
#define _HANDLER_
|
||||
|
||||
/** An abstract base class encapsulating the handlers for all commands
|
||||
understood by the system. */
|
||||
class Handler {
|
||||
public:
|
||||
virtual void ascii(char* arg) = 0;
|
||||
virtual void unicode(char* arg) = 0;
|
||||
virtual void procList(char* arg) = 0;
|
||||
virtual void attach(char* arg) = 0;
|
||||
virtual void detach(char* arg) = 0;
|
||||
virtual void libInfo(char* arg) = 0;
|
||||
virtual void peek(char* arg) = 0;
|
||||
virtual void poke(char* arg) = 0;
|
||||
virtual void threadList(char* arg) = 0;
|
||||
virtual void dupHandle(char* arg) = 0;
|
||||
virtual void closeHandle(char* arg) = 0;
|
||||
virtual void getContext(char* arg) = 0;
|
||||
virtual void setContext(char* arg) = 0;
|
||||
virtual void selectorEntry(char* arg) = 0;
|
||||
virtual void suspend(char* arg) = 0;
|
||||
virtual void resume(char* arg) = 0;
|
||||
virtual void pollEvent(char* arg) = 0;
|
||||
virtual void continueEvent(char* arg) = 0;
|
||||
virtual void exit(char* arg) = 0;
|
||||
};
|
||||
|
||||
#endif // #defined _HANDLER_
|
|
@ -1,490 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// This file is currently used for os/solaris/agent too. At some point in time
|
||||
// the source will be reorganized to avoid these ifdefs.
|
||||
|
||||
#ifdef __sun
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/byteorder.h>
|
||||
#endif
|
||||
|
||||
#include "IOBuf.hpp"
|
||||
|
||||
// Formats for printing pointers
|
||||
#ifdef _LP64
|
||||
# define INTPTR_FORMAT "0x%016lx"
|
||||
#else /* ! _LP64 */
|
||||
# define INTPTR_FORMAT "0x%08lx"
|
||||
#endif /* _LP64 */
|
||||
|
||||
// Uncomment the #define below to get messages on stderr
|
||||
// #define DEBUGGING
|
||||
|
||||
IOBuf::IOBuf(int inLen, int outLen) {
|
||||
inBuf = new Buffer(inLen);
|
||||
outBuf = new Buffer(outLen);
|
||||
fd = INVALID_SOCKET;
|
||||
outHandle = NULL;
|
||||
usingSocket = true;
|
||||
reset();
|
||||
}
|
||||
|
||||
IOBuf::~IOBuf() {
|
||||
delete inBuf;
|
||||
delete outBuf;
|
||||
}
|
||||
|
||||
void
|
||||
IOBuf::setSocket(SOCKET sock) {
|
||||
fd = sock;
|
||||
usingSocket = true;
|
||||
}
|
||||
|
||||
// Reading/writing files is only needed and used on windows.
|
||||
#ifdef WIN32
|
||||
void
|
||||
IOBuf::setOutputFileHandle(HANDLE handle) {
|
||||
outHandle = handle;
|
||||
usingSocket = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
IOBuf::reset() {
|
||||
gotDataLastTime = false;
|
||||
state = TEXT_STATE;
|
||||
binPos = 0;
|
||||
binLength = 0;
|
||||
}
|
||||
|
||||
IOBuf::ReadLineResult
|
||||
IOBuf::tryReadLine() {
|
||||
return doReadLine(false);
|
||||
}
|
||||
|
||||
char*
|
||||
IOBuf::readLine() {
|
||||
ReadLineResult rr = doReadLine(true);
|
||||
if (rr != RL_GOT_DATA) {
|
||||
return NULL;
|
||||
}
|
||||
return getLine();
|
||||
}
|
||||
|
||||
IOBuf::ReadLineResult
|
||||
IOBuf::doReadLine(bool shouldWait) {
|
||||
|
||||
if (!usingSocket) {
|
||||
return IOBuf::RL_ERROR;
|
||||
}
|
||||
|
||||
if (gotDataLastTime) {
|
||||
curLine.clear();
|
||||
}
|
||||
|
||||
int c;
|
||||
do {
|
||||
c = readChar(shouldWait);
|
||||
if (c >= 0) {
|
||||
Action act = processChar((char) c);
|
||||
if (act == GOT_LINE) {
|
||||
curLine.push_back('\0');
|
||||
gotDataLastTime = true;
|
||||
return IOBuf::RL_GOT_DATA;
|
||||
} else if (act == SKIP_EOL_CHAR) {
|
||||
// Do nothing
|
||||
} else {
|
||||
curLine.push_back((char) c);
|
||||
}
|
||||
}
|
||||
} while (shouldWait || c >= 0);
|
||||
|
||||
gotDataLastTime = false;
|
||||
return IOBuf::RL_NO_DATA;
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::flushImpl(bool moreDataToCome) {
|
||||
int numWritten = 0;
|
||||
|
||||
#ifdef WIN32
|
||||
// When running on Windows and using IOBufs for inter-process
|
||||
// communication, we need to write metadata into the stream
|
||||
// indicating how many bytes are coming down. Five bytes are written
|
||||
// per flush() call, four containing the integer number of bytes
|
||||
// coming (not including the five-byte header) and one (a 0 or 1)
|
||||
// indicating whether there is more data coming.
|
||||
if (!usingSocket) {
|
||||
int numToWrite = outBuf->drainRemaining();
|
||||
char moreToCome = (moreDataToCome ? 1 : 0);
|
||||
DWORD numBytesWritten;
|
||||
if (!WriteFile(outHandle, &numToWrite, sizeof(int), &numBytesWritten, NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (numBytesWritten != sizeof(int)) {
|
||||
return false;
|
||||
}
|
||||
if (!WriteFile(outHandle, &moreToCome, 1, &numBytesWritten, NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (numBytesWritten != 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
while (outBuf->drainRemaining() != 0) {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Flushing %d bytes\n", outBuf->drainRemaining());
|
||||
#endif
|
||||
if (usingSocket) {
|
||||
numWritten = send(fd, outBuf->drainPos(), outBuf->drainRemaining(), 0);
|
||||
} else {
|
||||
#ifdef WIN32
|
||||
DWORD numBytesWritten;
|
||||
if (!WriteFile(outHandle, outBuf->drainPos(), outBuf->drainRemaining(), &numBytesWritten, NULL)) {
|
||||
numWritten = -1;
|
||||
} else {
|
||||
numWritten = numBytesWritten;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (numWritten != -1) {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Flushed %d bytes\n", numWritten);
|
||||
#endif
|
||||
outBuf->incrDrainPos(numWritten);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
outBuf->compact();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
IOBuf::readChar(bool block) {
|
||||
do {
|
||||
int c = inBuf->readByte();
|
||||
if (c >= 0) {
|
||||
return c;
|
||||
}
|
||||
// See whether we need to compact the input buffer
|
||||
if (inBuf->remaining() < inBuf->size() / 2) {
|
||||
inBuf->compact();
|
||||
}
|
||||
// See whether socket is ready
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
if (block || select(1 + fd, &fds, NULL, NULL, &timeout) > 0) {
|
||||
if (block || FD_ISSET(fd, &fds)) {
|
||||
#ifdef DEBUGGING
|
||||
int b = (block ? 1 : 0);
|
||||
fprintf(stderr, "calling recv: block = %d\n", b);
|
||||
#endif
|
||||
// Read data from socket
|
||||
int numRead = recv(fd, inBuf->fillPos(), inBuf->remaining(), 0);
|
||||
if (numRead < 0) {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "recv failed\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
inBuf->incrFillPos(numRead);
|
||||
}
|
||||
}
|
||||
} while (block);
|
||||
|
||||
return inBuf->readByte();
|
||||
}
|
||||
|
||||
char*
|
||||
IOBuf::getLine() {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Returning (first 10 chars) \"%.10s\"\n", curLine.begin());
|
||||
#endif
|
||||
return curLine.begin();
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::flush() {
|
||||
return flushImpl(false);
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeString(const char* str) {
|
||||
int len = strlen(str);
|
||||
|
||||
if (len > outBuf->size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len > outBuf->remaining()) {
|
||||
if (!flushImpl(true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE we do not copy the null terminator of the string.
|
||||
|
||||
strncpy(outBuf->fillPos(), str, len);
|
||||
outBuf->incrFillPos(len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeInt(int val) {
|
||||
char buf[128];
|
||||
sprintf(buf, "%d", val);
|
||||
return writeString(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeUnsignedInt(unsigned int val) {
|
||||
char buf[128];
|
||||
sprintf(buf, "%u", val);
|
||||
return writeString(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBoolAsInt(bool val) {
|
||||
if (val) {
|
||||
return writeString("1");
|
||||
} else {
|
||||
return writeString("0");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeAddress(void* val) {
|
||||
char buf[128];
|
||||
sprintf(buf, INTPTR_FORMAT, val);
|
||||
return writeString(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeSpace() {
|
||||
return writeString(" ");
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeEOL() {
|
||||
return writeString("\n\r");
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBinChar(char c) {
|
||||
return writeBinBuf((char*) &c, sizeof(c));
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBinUnsignedShort(unsigned short i) {
|
||||
i = htons(i);
|
||||
return writeBinBuf((char*) &i, sizeof(i));
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBinUnsignedInt(unsigned int i) {
|
||||
i = htonl(i);
|
||||
return writeBinBuf((char*) &i, sizeof(i));
|
||||
}
|
||||
|
||||
bool
|
||||
IOBuf::writeBinBuf(char* buf, int size) {
|
||||
while (size > 0) {
|
||||
int spaceRemaining = outBuf->remaining();
|
||||
if (spaceRemaining == 0) {
|
||||
if (!flushImpl(true)) {
|
||||
return false;
|
||||
}
|
||||
spaceRemaining = outBuf->remaining();
|
||||
}
|
||||
int toCopy = (size > spaceRemaining) ? spaceRemaining : size;
|
||||
memcpy(outBuf->fillPos(), buf, toCopy);
|
||||
outBuf->incrFillPos(toCopy);
|
||||
buf += toCopy;
|
||||
size -= toCopy;
|
||||
if (size > 0) {
|
||||
if (!flushImpl(true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
IOBuf::FillState
|
||||
IOBuf::fillFromFileHandle(HANDLE fh, DWORD* numBytesRead) {
|
||||
int totalToRead;
|
||||
char moreToCome;
|
||||
|
||||
outBuf->compact();
|
||||
|
||||
DWORD numRead;
|
||||
if (!ReadFile(fh, &totalToRead, sizeof(int), &numRead, NULL)) {
|
||||
return FAILED;
|
||||
}
|
||||
if (numRead != sizeof(int)) {
|
||||
return FAILED;
|
||||
}
|
||||
if (!ReadFile(fh, &moreToCome, 1, &numRead, NULL)) {
|
||||
return FAILED;
|
||||
}
|
||||
if (numRead != 1) {
|
||||
return FAILED;
|
||||
}
|
||||
if (outBuf->remaining() < totalToRead) {
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
int tmp = totalToRead;
|
||||
|
||||
while (totalToRead > 0) {
|
||||
if (!ReadFile(fh, outBuf->fillPos(), totalToRead, &numRead, NULL)) {
|
||||
return FAILED;
|
||||
}
|
||||
outBuf->incrFillPos((int) numRead);
|
||||
totalToRead -= numRead;
|
||||
}
|
||||
|
||||
*numBytesRead = tmp;
|
||||
return ((moreToCome == 0) ? DONE : MORE_DATA_PENDING);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
IOBuf::isBinEscapeChar(char c) {
|
||||
return (c == '|');
|
||||
}
|
||||
|
||||
IOBuf::Action
|
||||
IOBuf::processChar(char c) {
|
||||
Action action = NO_ACTION;
|
||||
switch (state) {
|
||||
case TEXT_STATE: {
|
||||
// Looking for text char, bin escape char, or EOL
|
||||
if (isBinEscapeChar(c)) {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "[a: '%c'] ", inBuf[0]);
|
||||
#endif
|
||||
binPos = 0;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "[b: '%c'] ", inBuf[0]);
|
||||
#endif
|
||||
binLength = 0;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "[c: '%c'] ", inBuf[0]);
|
||||
#endif
|
||||
state = BIN_STATE;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "[d: '%c'] ", inBuf[0]);
|
||||
#endif
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "\nSwitching to BIN_STATE\n");
|
||||
#endif
|
||||
} else if (isEOL(c)) {
|
||||
state = EOL_STATE;
|
||||
action = GOT_LINE;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "\nSwitching to EOL_STATE (GOT_LINE)\n");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUGGING
|
||||
else {
|
||||
fprintf(stderr, "'%c' ", c);
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case BIN_STATE: {
|
||||
// Seeking to finish read of input
|
||||
if (binPos < 4) {
|
||||
int cur = c & 0xFF;
|
||||
binLength <<= 8;
|
||||
binLength |= cur;
|
||||
++binPos;
|
||||
} else {
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Reading binary byte %d of %d\n",
|
||||
binPos - 4, binLength);
|
||||
#endif
|
||||
++binPos;
|
||||
if (binPos == 4 + binLength) {
|
||||
state = TEXT_STATE;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "Switching to TEXT_STATE\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EOL_STATE: {
|
||||
// More EOL characters just cause us to re-enter this state
|
||||
if (isEOL(c)) {
|
||||
action = SKIP_EOL_CHAR;
|
||||
} else if (isBinEscapeChar(c)) {
|
||||
binPos = 0;
|
||||
binLength = 0;
|
||||
state = BIN_STATE;
|
||||
} else {
|
||||
state = TEXT_STATE;
|
||||
#ifdef DEBUGGING
|
||||
fprintf(stderr, "'%c' ", c);
|
||||
fflush(stderr);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} // switch
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IOBuf::isEOL(char c) {
|
||||
#ifdef WIN32
|
||||
return ((c == '\n') || (c == '\r'));
|
||||
#elif defined(__sun)
|
||||
return c == '\n';
|
||||
#else
|
||||
#error Please port isEOL() to your platform
|
||||
return false;
|
||||
#endif
|
||||
}
|
|
@ -1,222 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IO_BUF_
|
||||
#define _IO_BUF_
|
||||
|
||||
// This file is currently used for os/solaris/agent/ too. At some point in time
|
||||
// the source will be reorganized to avoid these ifdefs.
|
||||
// Note that this class can read/write from a file as well as a socket. This
|
||||
// file capability is only implemented on win32.
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
// These are from win32 winsock2.h
|
||||
typedef unsigned int SOCKET;
|
||||
typedef void * HANDLE;
|
||||
typedef unsigned long DWORD;
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include "Buffer.hpp"
|
||||
|
||||
/** Manages an input/output buffer pair for a socket or file handle. */
|
||||
class IOBuf {
|
||||
public:
|
||||
IOBuf(int inBufLen, int outBufLen);
|
||||
~IOBuf();
|
||||
|
||||
enum ReadLineResult {
|
||||
RL_GOT_DATA,
|
||||
RL_NO_DATA,
|
||||
RL_ERROR
|
||||
};
|
||||
|
||||
/** Change the socket with which this buffer is associated */
|
||||
void setSocket(SOCKET sock);
|
||||
|
||||
// Reading/writing files is only supported on windows.
|
||||
#ifdef WIN32
|
||||
/** Change the output file handle with which this buffer is
|
||||
associated. Currently IOBufs can not be used to read from a file
|
||||
handle. */
|
||||
void setOutputFileHandle(HANDLE handle);
|
||||
#endif
|
||||
|
||||
/** Reset the input and output buffers, without flushing the output
|
||||
data to the socket */
|
||||
void reset();
|
||||
|
||||
/** Try to read a line of data from the given socket without
|
||||
blocking. If was able to read a complete line of data, returns a
|
||||
character pointer to the beginning of the (null-terminated)
|
||||
string. If not, returns NULL, but maintains enough state that
|
||||
subsequent calls to tryReadLine() will not ignore the data
|
||||
already read. NOTE: this skips end-of-line characters (typically
|
||||
CR/LF) as defined by "isEOL()". When switching back and forth
|
||||
between binary and text modes, to be sure no data is lost, pad
|
||||
the beginning and end of the binary transmission with bytes
|
||||
which can not be confused with these characters. */
|
||||
ReadLineResult tryReadLine();
|
||||
|
||||
/** Read a line of data from the given socket, blocking until a
|
||||
line, including EOL, appears. Return the line, or NULL if
|
||||
something goes wrong. */
|
||||
char *readLine();
|
||||
|
||||
/** Get the pointer to the beginning of the (null-terminated) line.
|
||||
This should only be called if tryReadLine() has returned
|
||||
RL_GOT_DATA. This sets the "parsing cursor" to the beginning of
|
||||
the line. */
|
||||
char* getLine();
|
||||
|
||||
// NOTE: any further data-acquisition routines must ALWAYS call
|
||||
// fixupData() at the beginning!
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Output routines
|
||||
//
|
||||
|
||||
/** Flush the output buffer to the socket. Returns true if
|
||||
succeeded, false if write error occurred. */
|
||||
bool flush();
|
||||
|
||||
/** Write the given string to the output buffer. May flush if output
|
||||
buffer becomes too full to store the data. Not guaranteed to
|
||||
work if string is longer than the size of the output buffer.
|
||||
Does not include the null terminator of the string. Returns true
|
||||
if succeeded, false if write error occurred. */
|
||||
bool writeString(const char* str);
|
||||
|
||||
/** Write the given int to the output buffer. May flush if output
|
||||
buffer becomes too full to store the data. Returns true if
|
||||
succeeded, false if write error occurred. */
|
||||
bool writeInt(int val);
|
||||
|
||||
/** Write the given unsigned int to the output buffer. May flush if
|
||||
output buffer becomes too full to store the data. Returns true
|
||||
if succeeded, false if write error occurred. */
|
||||
bool writeUnsignedInt(unsigned int val);
|
||||
|
||||
/** Write the given boolean to the output buffer. May flush if
|
||||
output buffer becomes too full to store the data. Returns true
|
||||
if succeeded, false if write error occurred. */
|
||||
bool writeBoolAsInt(bool val);
|
||||
|
||||
/** Write the given address to the output buffer. May flush if
|
||||
output buffer becomes too full to store the data. Returns true
|
||||
if succeeded, false if write error occurred. */
|
||||
bool writeAddress(void* val);
|
||||
|
||||
/** Writes a space to the output buffer. May flush if output buffer
|
||||
becomes too full to store the data. Returns true if succeeded,
|
||||
false if write error occurred. */
|
||||
bool writeSpace();
|
||||
|
||||
/** Writes an end-of-line sequence to the output buffer. May flush
|
||||
if output buffer becomes too full to store the data. Returns
|
||||
true if succeeded, false if write error occurred. */
|
||||
bool writeEOL();
|
||||
|
||||
/** Writes a binary character to the output buffer. */
|
||||
bool writeBinChar(char c);
|
||||
|
||||
/** Writes a binary unsigned short in network (big-endian) byte
|
||||
order to the output buffer. */
|
||||
bool writeBinUnsignedShort(unsigned short i);
|
||||
|
||||
/** Writes a binary unsigned int in network (big-endian) byte order
|
||||
to the output buffer. */
|
||||
bool writeBinUnsignedInt(unsigned int i);
|
||||
|
||||
/** Writes a binary buffer to the output buffer. */
|
||||
bool writeBinBuf(char* buf, int size);
|
||||
|
||||
#ifdef WIN32
|
||||
enum FillState {
|
||||
DONE = 1,
|
||||
MORE_DATA_PENDING = 2,
|
||||
FAILED = 3
|
||||
};
|
||||
|
||||
/** Very specialized routine; fill the output buffer from the given
|
||||
file handle. Caller is responsible for ensuring that there is
|
||||
data to be read on the file handle. */
|
||||
FillState fillFromFileHandle(HANDLE fh, DWORD* numRead);
|
||||
#endif
|
||||
|
||||
/** Binary utility routine (for poke) */
|
||||
static bool isBinEscapeChar(char c);
|
||||
|
||||
private:
|
||||
IOBuf(const IOBuf&);
|
||||
IOBuf& operator=(const IOBuf&);
|
||||
|
||||
// Returns -1 if non-blocking and no data available
|
||||
int readChar(bool block);
|
||||
// Line-oriented reading
|
||||
std::vector<char> curLine;
|
||||
bool gotDataLastTime;
|
||||
|
||||
ReadLineResult doReadLine(bool);
|
||||
|
||||
bool flushImpl(bool moreDataToCome);
|
||||
|
||||
SOCKET fd;
|
||||
HANDLE outHandle;
|
||||
bool usingSocket;
|
||||
|
||||
// Buffers
|
||||
Buffer* inBuf;
|
||||
Buffer* outBuf;
|
||||
|
||||
// Simple finite-state machine to handle binary data
|
||||
enum State {
|
||||
TEXT_STATE,
|
||||
BIN_STATE,
|
||||
EOL_STATE
|
||||
};
|
||||
enum Action {
|
||||
NO_ACTION,
|
||||
GOT_LINE, // TEXT_STATE -> EOL_STATE transition
|
||||
SKIP_EOL_CHAR // EOL_STATE -> EOL_STATE transition
|
||||
};
|
||||
|
||||
State state;
|
||||
Action processChar(char c);
|
||||
|
||||
// Handling incoming binary buffers (poke command)
|
||||
int binPos; // Number of binary characters read so far;
|
||||
// total number to read is binLength + 4
|
||||
int binLength; // Number of binary characters in message;
|
||||
// not valid until binPos >= 4
|
||||
|
||||
bool isEOL(char c);
|
||||
};
|
||||
|
||||
#endif // #defined _IO_BUF_
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LOCKABLE_LIST_
|
||||
#define _LOCKABLE_LIST_
|
||||
|
||||
#include <windows.h>
|
||||
#include "BasicList.hpp"
|
||||
|
||||
template<class T>
|
||||
class LockableList : public BasicList<T> {
|
||||
private:
|
||||
CRITICAL_SECTION crit;
|
||||
|
||||
public:
|
||||
LockableList() {
|
||||
InitializeCriticalSection(&crit);
|
||||
}
|
||||
|
||||
~LockableList() {
|
||||
DeleteCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void lock() {
|
||||
EnterCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
LeaveCriticalSection(&crit);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // #defined _LOCKABLE_LIST_
|
|
@ -1,80 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
#
|
||||
|
||||
SERVER=SwDbgSrv.exe
|
||||
SUBPROCESS=SwDbgSub.exe
|
||||
|
||||
SERVER_SOURCES = \
|
||||
Buffer.cpp \
|
||||
Dispatcher.cpp \
|
||||
initWinsock.cpp \
|
||||
IOBuf.cpp \
|
||||
ioUtils.cpp \
|
||||
isNT4.cpp \
|
||||
nt4internals.cpp \
|
||||
procList.cpp \
|
||||
Reaper.cpp \
|
||||
SwDbgSrv.cpp \
|
||||
serverLists.cpp \
|
||||
toolHelp.cpp
|
||||
|
||||
SUBPROCESS_SOURCES = \
|
||||
SwDbgSub.cpp \
|
||||
Buffer.cpp \
|
||||
IOBuf.cpp \
|
||||
isNT4.cpp \
|
||||
libInfo.cpp \
|
||||
Monitor.cpp \
|
||||
nt4internals.cpp \
|
||||
toolHelp.cpp
|
||||
|
||||
SERVER_OBJS = $(SERVER_SOURCES:.cpp=.obj)
|
||||
SUBPROCESS_OBJS = $(SUBPROCESS_SOURCES:.cpp=.obj)
|
||||
|
||||
CPP=cl.exe
|
||||
LINK32=link.exe
|
||||
|
||||
# These do not need to be optimized (don't run a lot of code) and it
|
||||
# will be useful to have the assertion checks in place
|
||||
|
||||
CFLAGS=/nologo /MD /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
|
||||
LIBS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib \
|
||||
ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib \
|
||||
winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib \
|
||||
odbccp32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386
|
||||
|
||||
default: $(SERVER) $(SUBPROCESS)
|
||||
|
||||
$(SERVER): $(SERVER_OBJS)
|
||||
$(LINK32) /out:$@ $(SERVER_OBJS) $(LIBS)
|
||||
|
||||
$(SUBPROCESS): $(SUBPROCESS_OBJS)
|
||||
$(LINK32) /out:$@ $(SUBPROCESS_OBJS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f *.obj *.idb *.pch *.pdb *.ncb *.opt *.plg *.exe *.ilk
|
||||
|
||||
.cpp.obj:
|
||||
@ $(CPP) $(CFLAGS) /o $@ $<
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MESSAGE_
|
||||
#define _MESSAGE_
|
||||
|
||||
// These are the commands sent from the server to the child processes
|
||||
// over the child processes' stdin pipes. A subset of the commands
|
||||
// understood by the overall system, these require responses from the
|
||||
// child process. Having a data structure rather than sending text
|
||||
// simplifies parsing on the child side. The child replies by sending
|
||||
// back fully-formatted replies which are copied by the server process
|
||||
// to the clients' sockets.
|
||||
|
||||
struct PeekArg {
|
||||
DWORD address;
|
||||
DWORD numBytes;
|
||||
};
|
||||
|
||||
// NOTE: when sending a PokeArg to the child process, we handle the
|
||||
// buffer specially
|
||||
struct PokeArg {
|
||||
DWORD address;
|
||||
DWORD numBytes;
|
||||
void* data;
|
||||
};
|
||||
|
||||
// Used for continueevent
|
||||
struct BoolArg {
|
||||
bool val;
|
||||
};
|
||||
|
||||
// Used for duphandle, closehandle, and getcontext
|
||||
struct HandleArg {
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
// Used for setcontext
|
||||
const int NUM_REGS_IN_CONTEXT = 22;
|
||||
struct SetContextArg {
|
||||
HANDLE handle;
|
||||
DWORD Eax;
|
||||
DWORD Ebx;
|
||||
DWORD Ecx;
|
||||
DWORD Edx;
|
||||
DWORD Esi;
|
||||
DWORD Edi;
|
||||
DWORD Ebp;
|
||||
DWORD Esp;
|
||||
DWORD Eip;
|
||||
DWORD Ds;
|
||||
DWORD Es;
|
||||
DWORD Fs;
|
||||
DWORD Gs;
|
||||
DWORD Cs;
|
||||
DWORD Ss;
|
||||
DWORD EFlags;
|
||||
DWORD Dr0;
|
||||
DWORD Dr1;
|
||||
DWORD Dr2;
|
||||
DWORD Dr3;
|
||||
DWORD Dr6;
|
||||
DWORD Dr7;
|
||||
};
|
||||
|
||||
// Used for selectorentry
|
||||
struct SelectorEntryArg {
|
||||
HANDLE handle;
|
||||
DWORD selector;
|
||||
};
|
||||
|
||||
struct Message {
|
||||
typedef enum {
|
||||
ATTACH,
|
||||
DETACH,
|
||||
LIBINFO,
|
||||
PEEK,
|
||||
POKE,
|
||||
THREADLIST,
|
||||
DUPHANDLE,
|
||||
CLOSEHANDLE,
|
||||
GETCONTEXT,
|
||||
SETCONTEXT,
|
||||
SELECTORENTRY,
|
||||
SUSPEND,
|
||||
RESUME,
|
||||
POLLEVENT,
|
||||
CONTINUEEVENT
|
||||
} Type;
|
||||
|
||||
Type type;
|
||||
union {
|
||||
PeekArg peekArg;
|
||||
PokeArg pokeArg;
|
||||
BoolArg boolArg;
|
||||
HandleArg handleArg;
|
||||
SetContextArg setContextArg;
|
||||
SelectorEntryArg selectorArg;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // #defined _MESSAGE_
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "Monitor.hpp"
|
||||
|
||||
Monitor::Monitor() {
|
||||
_lock_count = -1; // No threads have entered the critical section
|
||||
_owner = NULL;
|
||||
_lock_event = CreateEvent(NULL, false, false, NULL);
|
||||
_wait_event = CreateEvent(NULL, true, false, NULL);
|
||||
_counter = 0;
|
||||
_tickets = 0;
|
||||
_waiters = 0;
|
||||
}
|
||||
|
||||
Monitor::~Monitor() {
|
||||
assert(_owner == NULL); // Otherwise, owned monitor being deleted
|
||||
assert(_lock_count == -1); // Otherwise, monitor being deleted with non -1 lock count
|
||||
CloseHandle(_lock_event);
|
||||
CloseHandle(_wait_event);
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::lock() {
|
||||
if (InterlockedIncrement(&_lock_count) == 0) {
|
||||
// Success, we now own the lock
|
||||
} else {
|
||||
DWORD dwRet = WaitForSingleObject((HANDLE)_lock_event, INFINITE);
|
||||
assert(dwRet == WAIT_OBJECT_0); // Unexpected return value from WaitForSingleObject
|
||||
}
|
||||
assert(owner() == NULL); // Otherwise, lock count and owner are inconsistent
|
||||
setOwner(GetCurrentThread());
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::unlock() {
|
||||
setOwner(NULL);
|
||||
if (InterlockedDecrement(&_lock_count) >= 0) {
|
||||
// Wake a waiting thread up
|
||||
DWORD dwRet = SetEvent(_lock_event);
|
||||
assert(dwRet != 0); // Unexpected return value from SetEvent
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Monitor::wait(long timeout) {
|
||||
assert(owner() != NULL);
|
||||
assert(owner() == GetCurrentThread());
|
||||
|
||||
// 0 means forever. Convert to Windows specific code.
|
||||
DWORD timeout_value = (timeout == 0) ? INFINITE : timeout;
|
||||
DWORD which;
|
||||
|
||||
long c = _counter;
|
||||
bool retry = false;
|
||||
|
||||
_waiters++;
|
||||
// Loop until condition variable is signaled. The event object is
|
||||
// set whenever the condition variable is signaled, and tickets will
|
||||
// reflect the number of threads which have been notified. The counter
|
||||
// field is used to make sure we don't respond to notifications that
|
||||
// have occurred *before* we started waiting, and is incremented each
|
||||
// time the condition variable is signaled.
|
||||
|
||||
while (true) {
|
||||
|
||||
// Leave critical region
|
||||
unlock();
|
||||
|
||||
// If this is a retry, let other low-priority threads have a chance
|
||||
// to run. Make sure that we sleep outside of the critical section.
|
||||
if (retry) {
|
||||
Sleep(1);
|
||||
} else {
|
||||
retry = true;
|
||||
}
|
||||
|
||||
which = WaitForSingleObject(_wait_event, timeout_value);
|
||||
// Enter critical section
|
||||
lock();
|
||||
|
||||
if (_tickets != 0 && _counter != c) break;
|
||||
|
||||
if (which == WAIT_TIMEOUT) {
|
||||
--_waiters;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_waiters--;
|
||||
|
||||
// If this was the last thread to be notified, then we need to reset
|
||||
// the event object.
|
||||
if (--_tickets == 0) {
|
||||
ResetEvent(_wait_event);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Notify a single thread waiting on this monitor
|
||||
bool
|
||||
Monitor::notify() {
|
||||
assert(ownedBySelf()); // Otherwise, notify on unknown thread
|
||||
|
||||
if (_waiters > _tickets) {
|
||||
if (!SetEvent(_wait_event)) {
|
||||
return false;
|
||||
}
|
||||
_tickets++;
|
||||
_counter++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Notify all threads waiting on this monitor
|
||||
bool
|
||||
Monitor::notifyAll() {
|
||||
assert(ownedBySelf()); // Otherwise, notifyAll on unknown thread
|
||||
|
||||
if (_waiters > 0) {
|
||||
if (!SetEvent(_wait_event)) {
|
||||
return false;
|
||||
}
|
||||
_tickets = _waiters;
|
||||
_counter++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
Monitor::owner() {
|
||||
return _owner;
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::setOwner(HANDLE owner) {
|
||||
if (owner != NULL) {
|
||||
assert(_owner == NULL); // Setting owner thread of already owned monitor
|
||||
assert(owner == GetCurrentThread()); // Else should not be doing this
|
||||
} else {
|
||||
HANDLE oldOwner = _owner;
|
||||
assert(oldOwner != NULL); // Removing the owner thread of an unowned mutex
|
||||
assert(oldOwner == GetCurrentThread());
|
||||
}
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
bool
|
||||
Monitor::ownedBySelf() {
|
||||
return (_owner == GetCurrentThread());
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MONITOR_
|
||||
#define _MONITOR_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
Monitor();
|
||||
~Monitor();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
// Default time is forever (i.e, zero). Returns true if it times-out, otherwise
|
||||
// false.
|
||||
bool wait(long timeout = 0);
|
||||
bool notify();
|
||||
bool notifyAll();
|
||||
|
||||
private:
|
||||
HANDLE owner();
|
||||
void setOwner(HANDLE owner);
|
||||
bool ownedBySelf();
|
||||
|
||||
HANDLE _owner;
|
||||
long _lock_count;
|
||||
HANDLE _lock_event; // Auto-reset event for blocking in lock()
|
||||
HANDLE _wait_event; // Manual-reset event for notifications
|
||||
long _counter; // Current number of notifications
|
||||
long _waiters; // Number of threads waiting for notification
|
||||
long _tickets; // Number of waiters to be notified
|
||||
};
|
||||
|
||||
|
||||
#endif // #defined _MONITOR_
|
|
@ -1,246 +0,0 @@
|
|||
This debug server uses a largely text-based protocol, except for
|
||||
certain bulk data transfer operations. All text is in single-byte
|
||||
US-ASCII except for the strings returned in "proclist".
|
||||
|
||||
NOTE that the character '|' (vertical bar) is used as an escape
|
||||
character to switch the incoming data stream to the debug server into
|
||||
binary mode, so no text command may contain that character.
|
||||
|
||||
Commands understood:
|
||||
|
||||
ascii <EOL> ::=
|
||||
|
||||
Changes to ASCII mode. This affects all outgoing strings. At
|
||||
startup the system is in unicode mode.
|
||||
|
||||
unicode <EOL> ::=
|
||||
|
||||
Changes to UNICODE mode. This affects all outgoing strings. This
|
||||
is the default mode upon startup.
|
||||
|
||||
proclist <EOL> ::=
|
||||
<int num> [<unsigned int pid> <int charSize> <int numChars> [<binary char_t name>]...]... <EOL>
|
||||
|
||||
Returns integer indicating number of processes to follow, followed
|
||||
by (pid, name) pairs. Names are given by (charSize, numChars,
|
||||
[char_t]...) tuples; charSize indicates the size of each character
|
||||
in bytes, numChars the number of characters in the string, and
|
||||
name the raw data for the string. Each individual character of the
|
||||
string, if multi-byte, is transmitted in network byte order.
|
||||
numChars and name are guaranteed to be separated by precisely one
|
||||
US-ASCII space. If process list is not available because of
|
||||
limitations of the underlying operating system, number of
|
||||
processes returned is 0.
|
||||
|
||||
attach <int pid> <EOL> ::= <bool result> <EOL>
|
||||
|
||||
Attempts to attach to the specified process. Returns 1 if
|
||||
successful, 0 if not. Will fail if already attached or if the
|
||||
process ID does not exist. Attaching to a process causes the
|
||||
process to be suspended.
|
||||
|
||||
detach <EOL> ::= <bool result> <EOL>
|
||||
|
||||
Detaches from the given process. Attaching and detaching multiple
|
||||
times during a debugging session is allowed. Detaching causes the
|
||||
process to resume execution.
|
||||
|
||||
libinfo <EOL> ::=
|
||||
<int numLibs> [<int charSize> <int numChars> [<binary char_t name>]... <address baseAddr>]... <EOL>
|
||||
|
||||
May only be called once attached and the target process must be
|
||||
suspended; otherwise, returns 0. Returns list of the full path
|
||||
names of all of the loaded modules (including the executable
|
||||
image) in the target process, as well as the base address at which
|
||||
each module was relocated. See proclist for format of strings, but
|
||||
NOTE that charSize is ALWAYS 1 for this particular routine,
|
||||
regardless of the setting of ASCII/UNICODE.
|
||||
|
||||
peek <address addr> <unsigned int numBytes> <EOL> ::=
|
||||
B<binary char success>
|
||||
[<binary unsigned int len> <binary char isMapped> [<binary char data>]...]...
|
||||
|
||||
NOTE that the binary portion of this message is prefixed by the
|
||||
uppercase US-ASCII letter 'B', allowing easier synchronization by
|
||||
clients. There is no data between the 'B' and the rest of the
|
||||
message.
|
||||
|
||||
May only be called once attached. Reads the address space of the
|
||||
target process starting at the given address (see below for format
|
||||
specifications) and extending the given number of bytes. Whether
|
||||
the read succeeded is indicated by a single byte containing a 1 or
|
||||
0 (success or failure). If successful, the return result is given
|
||||
in a sequence of ranges. _len_, the length of each range, is
|
||||
indicated by a 32-bit unsigned integer transmitted with big-endian
|
||||
byte ordering (i.e., most significant byte first). _isMapped_
|
||||
indicates whether the range is mapped or unmapped in the target
|
||||
process's address space, and will contain the value 1 or 0 for
|
||||
mapped or unmapped, respectively. If the range is mapped,
|
||||
_isMapped_ is followed by _data_, containing the raw binary data
|
||||
for the range. The sum of all ranges' lengths is guaranteed to be
|
||||
equivalent to the number of bytes requested.
|
||||
|
||||
poke <address addr> |[<binary unsigned int len> [<binary char data>]] <EOL> ::=
|
||||
<bool result> <EOL>
|
||||
|
||||
NOTE that the binary portion of this message is prefixed by the
|
||||
uppercase US-ASCII character '|' (vertical bar), allowing easier
|
||||
synchronization by the server. There is no data between the '|'
|
||||
and the rest of the message. ('B' is not used here because
|
||||
addresses can contain that letter; no alphanumeric characters are
|
||||
used because some of the parsing routines are used by the Solaris
|
||||
SA port, and in that port any alphanumeric character can show up
|
||||
as a part of a symbol being looked up.)
|
||||
|
||||
May only be called once attached. Writes the address space of the
|
||||
target process starting at the given address (see below for format
|
||||
specifications), extending the given number of bytes, and
|
||||
containing the given data. The number of bytes is a 32-bit
|
||||
unsigned integer transmitted with big-endian byte ordering (i.e.,
|
||||
most significant byte first). This is followed by the raw binary
|
||||
data to be placed at that address. The number of bytes of data
|
||||
must match the number of bytes specified in the message.
|
||||
|
||||
Returns true if the write succeeded; false if it failed, for
|
||||
example because a portion of the region was not mapped in the
|
||||
target address space.
|
||||
|
||||
threadlist <EOL> ::= <int numThreads> [<address threadHandle>...] <EOL>
|
||||
|
||||
May only be called once attached and the target process must be
|
||||
suspended; otherwise, returns 0. If available, returns handles for
|
||||
all of the threads in the target process. These handles may be
|
||||
used as arguments to the getcontext and selectorentry
|
||||
commands. They do not need to be (and should not be) duplicated
|
||||
via the duphandle command and must not be closed via the
|
||||
closehandle command.
|
||||
|
||||
duphandle <address handle> <EOL> ::=
|
||||
<bool success> [<address duplicate>] <EOL>
|
||||
|
||||
Duplicates a HANDLE read from the target process's address space.
|
||||
HANDLE is a Windows construct (typically typedef'd to void *).
|
||||
The returned handle should ultimately be closed via the
|
||||
closehandle command; failing to do so can cause resource leaks.
|
||||
|
||||
The purpose of this command is to allow the debugger to read the
|
||||
value of a thread handle from the target process and query its
|
||||
register set and thread selector entries via the getcontext and
|
||||
selectorentry commands, below; such use implies that the target
|
||||
program has its own notion of the thread list, and further, that
|
||||
the debugger has a way of locating that thread list.
|
||||
|
||||
closehandle <address handle> <EOL> ::=
|
||||
|
||||
Closes a handle retrieved via the duphandle command, above.
|
||||
|
||||
getcontext <address threadHandle> <EOL> ::= <bool success> [<context>] <EOL>
|
||||
|
||||
Returns the context for the given thread. The handle must either
|
||||
be one of the handles returned from the threadlist command or the
|
||||
result of duplicating a thread handle out of the target process
|
||||
via the duphandle command. The target process must be suspended.
|
||||
|
||||
The context is returned as a series of hex values which represent
|
||||
the following x86 registers in the following order:
|
||||
EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EIP, DS, ES, FS, GS,
|
||||
CS, SS, EFLAGS, DR0, DR1, DR2, DR3, DR6, DR7
|
||||
|
||||
FIXME: needs to be generalized and/or specified for other
|
||||
architectures.
|
||||
|
||||
setcontext <address threadHandle> <context> ::= <bool success> <EOL>
|
||||
|
||||
Sets the context of the given thread. The target process must be
|
||||
suspended. See the getcontext command for the ordering of the
|
||||
registers in the context.
|
||||
|
||||
Even if the setcontext command succeeds, some of the bits in some
|
||||
of the registers (like the global enable bits in the debug
|
||||
registers) may be overridden by the operating system. To ensure
|
||||
the debugger's notion of the register set is up to date, it is
|
||||
recommended to follow up a setcontext with a getcontext.
|
||||
|
||||
selectorentry <address threadHandle> <int selector> <EOL> ::=
|
||||
<bool success>
|
||||
[<address limitLow> <address baseLow>
|
||||
<address baseMid> <address flags1>
|
||||
<address flags2> <address baseHi>] <EOL>
|
||||
|
||||
Retrieves a descriptor table entry for the given thread and
|
||||
selector. This data structure allows conversion of a
|
||||
segment-relative address to a linear virtual address. It is most
|
||||
useful for locating the Thread Information Block for a given
|
||||
thread handle to be able to find that thread's ID, to be able to
|
||||
understand whether two different thread handles in fact refer to
|
||||
the same underlying thread.
|
||||
|
||||
This command will only work on the X86 architecture and will
|
||||
return false for the success flag (with no additional information
|
||||
sent) on other architectures.
|
||||
|
||||
suspend ::=
|
||||
|
||||
Suspends the target process. Must be attached to a target process.
|
||||
A process is suspended when attached to via the attach command. If
|
||||
the target process is already suspended then this command has no
|
||||
effect.
|
||||
|
||||
resume ::=
|
||||
|
||||
Resumes the target process without detaching from it. Must be
|
||||
attached to a target process. After resuming a target process, the
|
||||
debugger client must be prepared to poll for events from the
|
||||
target process fairly frequently in order for execution in the
|
||||
target process to proceed normally. If the target process is
|
||||
already resumed then this command has no effect.
|
||||
|
||||
pollevent ::=
|
||||
<bool eventPresent> [<address threadHandle> <unsigned int eventCode>]
|
||||
|
||||
Additional entries in result for given eventCode:
|
||||
|
||||
LOAD/UNLOAD_DLL_DEBUG_EVENT: <address baseOfDLL>
|
||||
EXCEPTION_DEBUG_EVENT: <unsigned int exceptionCode> <address faultingPC>
|
||||
|
||||
Additional entries for given exceptionCode:
|
||||
|
||||
EXCEPTION_ACCESS_VIOLATION: <bool wasWrite> <address faultingAddress>
|
||||
|
||||
<EOL>
|
||||
|
||||
Polls once to see whether a debug event has been generated by the
|
||||
target process. If none is present, returns 0 immediately.
|
||||
Otherwise, returns 1 along with a series of textual information
|
||||
about the event. The event is not cleared, and the thread resumed,
|
||||
until the continueevent command is sent, or the debugger client
|
||||
detaches from the target process.
|
||||
|
||||
Typically a debugger client will suspend the target process upon
|
||||
reception of a debug event. Otherwise, it is not guaranteed that
|
||||
all threads will be suspended upon reception of a debug event, and
|
||||
any operations requiring that threads be suspended (including
|
||||
fetching the context for the thread which generated the event)
|
||||
will fail.
|
||||
|
||||
continueevent <bool passEventToClient> ::= <bool success> <EOL>
|
||||
|
||||
Indicates that the current debug event has been used by the
|
||||
debugger client and that the target process should be resumed. The
|
||||
passEventToClient flag indicates whether the event should be
|
||||
propagated to the target process. Breakpoint and single-step
|
||||
events should not be propagated to the target. Returns false if
|
||||
there was no pending event, true otherwise.
|
||||
|
||||
exit <EOL>
|
||||
|
||||
Exits this debugger session.
|
||||
|
||||
Format specifications:
|
||||
|
||||
// Data formats and example values:
|
||||
<EOL> ::= end of line (typically \n on Unix platforms, or \n\r on Windows)
|
||||
<address> ::= 0x12345678[9ABCDEF0] /* up to 64-bit hex value */
|
||||
<unsigned int> ::= 5 /* up to 32-bit integer number; no leading sign */
|
||||
<bool> ::= 1 /* ASCII '0' or '1' */
|
||||
<context> ::= <address> ...
|
|
@ -1,64 +0,0 @@
|
|||
This is a "Simple Windows Debug Server" written for the purpose of
|
||||
enabling the Serviceability Agent on Win32. It has backends both for
|
||||
Windows NT 4.0 (using internal Windows APIs for a few routines) as
|
||||
well as for 95/98/ME/2000 via the Tool Help APIs.
|
||||
|
||||
The reason this debug server is necessary is that the Win32 debug APIs
|
||||
by design tear down the target process when the debugger exits (see
|
||||
knowledge base article Q164205 on msdn.microsoft.com). On Solaris, one
|
||||
can attach to and detach from a process with no effect; this is key to
|
||||
allowing dbx and gcore to work.
|
||||
|
||||
The Simple Windows Debug Server effectively implements attach/detach
|
||||
functionality for arbitrary debug clients. This allows the SA to
|
||||
attach non-destructively to a process, and will enable gcore for Win32
|
||||
to be written shortly. While the debugger (the "client" in all of the
|
||||
source code) is attached, the target process is suspended. (Note that
|
||||
the debug server could be extended to support resumption of the target
|
||||
process and transmission of debug events over to the debugger, but
|
||||
this has been left for the future.)
|
||||
|
||||
The makefile (type "nmake") builds two executables: SwDbgSrv.exe,
|
||||
which is the server process, and SwDbgSub.exe, which is forked by the
|
||||
server and should not be directly invoked by the user.
|
||||
|
||||
The intent is that these two executables can be installed into
|
||||
C:\WINNT\SYSTEM32 and SwDbgSrv installed to run as a service (on NT),
|
||||
for example using ServiceInstaller (http://www.kcmultimedia.com/smaster/).
|
||||
However, SwDbgSrv can also be run from the command line. It generates
|
||||
no text output unless the source code is changed to enable debugging
|
||||
printouts. As long as any processes which have been attached to by the
|
||||
SA are alive, the SwDbgSrv and any forked SwDbgSub processes must be
|
||||
left running. Terminating them will cause termination of the target
|
||||
processes.
|
||||
|
||||
The debug server opens port 27000 and accepts incoming connections
|
||||
from localhost only. The security model assumes that if one can run a
|
||||
process on the given machine then one basically has access to most or
|
||||
all of the machine's facilities; this seems to be in line with the
|
||||
standard Windows security model. The protocol used is text-based, so
|
||||
one can debug the debug server using telnet. See README-commands.txt
|
||||
for documentation on the supported commands.
|
||||
|
||||
Testing indicates that the performance impact of attaching to a
|
||||
process (and therefore permanently attaching a debugger) is minimal.
|
||||
Some serious performance problems had been seen which ultimately
|
||||
appeared to be a lack of physical memory on the machine running the
|
||||
system.
|
||||
|
||||
Bugs:
|
||||
|
||||
This debug server is fundamentally incompatible with the Visual C++
|
||||
debugger. Once the debug server is used to attach to a process, the
|
||||
Visual C++ IDE will not be able to attach to the same process (even if
|
||||
the debug server is "detached" from that process). Note that this
|
||||
system is designed to work with the same primitives that C and C++
|
||||
debuggers use (like "symbol lookup" and "read from process memory")
|
||||
and exposes these primitives to Java, so in the long term we could
|
||||
solve this problem by implementing platform-specific debug symbol
|
||||
parsing and a platform-independent C++ debugger in Java.
|
||||
|
||||
Note:
|
||||
|
||||
The files IOBuf.cpp and IOBuf.hpp are also used in
|
||||
building src/os/solaris/agent.
|
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "Reaper.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Reaper::Reaper(ReaperCB* cb) {
|
||||
InitializeCriticalSection(&crit);
|
||||
event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
this->cb = cb;
|
||||
|
||||
active = false;
|
||||
shouldShutDown = false;
|
||||
}
|
||||
|
||||
bool
|
||||
Reaper::start() {
|
||||
bool result = false;
|
||||
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
if (!active) {
|
||||
DWORD id;
|
||||
HANDLE reaper = CreateThread(NULL, 0, &Reaper::reaperThreadEntry,
|
||||
this, 0, &id);
|
||||
if (reaper != NULL) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
Reaper::stop() {
|
||||
bool result = false;
|
||||
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
if (active) {
|
||||
shouldShutDown = true;
|
||||
SetEvent(event);
|
||||
while (active) {
|
||||
Sleep(1);
|
||||
}
|
||||
shouldShutDown = false;
|
||||
result = true;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
Reaper::registerProcess(HANDLE processHandle, void* userData) {
|
||||
ProcessInfo info;
|
||||
|
||||
info.handle = processHandle;
|
||||
info.userData = userData;
|
||||
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
procInfo.push_back(info);
|
||||
SetEvent(event);
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void
|
||||
Reaper::reaperThread() {
|
||||
while (!shouldShutDown) {
|
||||
// Take atomic snapshot of the current process list and user data
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
int num = procInfo.size();
|
||||
HANDLE* handleList = new HANDLE[1 + num];
|
||||
void** dataList = new void*[num];
|
||||
for (int i = 0; i < num; i++) {
|
||||
handleList[i] = procInfo[i].handle;
|
||||
dataList[i] = procInfo[i].userData;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
|
||||
// Topmost handle becomes the event object, so other threads can
|
||||
// signal this one to notice differences in the above list (or
|
||||
// shut down)
|
||||
handleList[num] = event;
|
||||
|
||||
// Wait for these objects
|
||||
DWORD idx = WaitForMultipleObjects(1 + num, handleList,
|
||||
FALSE, INFINITE);
|
||||
if ((idx >= WAIT_OBJECT_0) && (idx <= WAIT_OBJECT_0 + num)) {
|
||||
idx -= WAIT_OBJECT_0;
|
||||
if (idx < num) {
|
||||
// A process exited (i.e., it wasn't that we were woken up
|
||||
// just because the event went off)
|
||||
(*cb)(dataList[idx]);
|
||||
// Remove this process from the list (NOTE: requires that
|
||||
// ordering does not change, i.e., that all additions are to
|
||||
// the back of the process list)
|
||||
EnterCriticalSection(&crit);
|
||||
|
||||
std::vector<ProcessInfo>::iterator iter = procInfo.begin();
|
||||
iter += idx;
|
||||
procInfo.erase(iter);
|
||||
|
||||
LeaveCriticalSection(&crit);
|
||||
} else {
|
||||
// Notification from other thread
|
||||
ResetEvent(event);
|
||||
}
|
||||
} else {
|
||||
// Unexpected return value. For now, warn.
|
||||
cerr << "Reaper::reaperThread(): unexpected return value "
|
||||
<< idx << " from WaitForMultipleObjects" << endl;
|
||||
}
|
||||
|
||||
// Clean up these lists
|
||||
delete[] handleList;
|
||||
delete[] dataList;
|
||||
}
|
||||
|
||||
// Time to shut down
|
||||
active = false;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
Reaper::reaperThreadEntry(LPVOID data) {
|
||||
Reaper* reaper = (Reaper*) data;
|
||||
reaper->reaperThread();
|
||||
return 0;
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _REAPER_
|
||||
#define _REAPER_
|
||||
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
typedef void ReaperCB(void* userData);
|
||||
|
||||
/** A Reaper maintains a thread which waits for child processes to
|
||||
terminate; upon termination it calls a user-specified ReaperCB to
|
||||
clean up resources associated with those child processes. */
|
||||
|
||||
class Reaper {
|
||||
private:
|
||||
Reaper& operator=(const Reaper&);
|
||||
Reaper(const Reaper&);
|
||||
|
||||
public:
|
||||
Reaper(ReaperCB*);
|
||||
~Reaper();
|
||||
|
||||
// Start the reaper thread.
|
||||
bool start();
|
||||
|
||||
// Stop the reaper thread. This is called automatically in the
|
||||
// reaper's destructor. It is not thread safe and should be called
|
||||
// by at most one thread at a time.
|
||||
bool stop();
|
||||
|
||||
// Register a given child process with the reaper. This should be
|
||||
// called by the application's main thread. When that process
|
||||
// terminates, the cleanup callback will be called with the
|
||||
// specified userData in the context of the reaper thread. Callbacks
|
||||
// are guaranteed to be called serially, so they can safely refer to
|
||||
// static data as well as the given user data.
|
||||
void registerProcess(HANDLE processHandle, void* userData);
|
||||
|
||||
private:
|
||||
// For thread safety of register()
|
||||
CRITICAL_SECTION crit;
|
||||
|
||||
ReaperCB* cb;
|
||||
|
||||
// State variables
|
||||
volatile bool active;
|
||||
volatile bool shouldShutDown;
|
||||
|
||||
struct ProcessInfo {
|
||||
HANDLE handle;
|
||||
void* userData;
|
||||
};
|
||||
|
||||
// Bookkeeping
|
||||
std::vector<ProcessInfo> procInfo;
|
||||
|
||||
// Synchronization between application thread and reaper thread
|
||||
HANDLE event;
|
||||
|
||||
// Entry point for reaper thread
|
||||
void reaperThread();
|
||||
|
||||
// Static function which is actual thread entry point
|
||||
static DWORD WINAPI reaperThreadEntry(LPVOID data);
|
||||
};
|
||||
|
||||
#endif // #defined _REAPER_
|
File diff suppressed because it is too large
Load diff
|
@ -1,146 +0,0 @@
|
|||
# Microsoft Developer Studio Project File - Name="SwDbgSrv" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=SwDbgSrv - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "SwDbgSrv.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "SwDbgSrv.mak" CFG="SwDbgSrv - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "SwDbgSrv - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "SwDbgSrv - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "SwDbgSrv - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "SwDbgSrv - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "SwDbgSrv___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "SwDbgSrv___Win32_Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "SwDbgSrv - Win32 Release"
|
||||
# Name "SwDbgSrv - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Buffer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Dispatcher.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\initWinsock.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IOBuf.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ioUtils.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\isNT4.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\nt4internals.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\procList.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Reaper.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\serverLists.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\SwDbgSrv.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\toolHelp.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
|
@ -1,41 +0,0 @@
|
|||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "SwDbgSrv"=.\SwDbgSrv.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "SwDbgSub"=.\SwDbgSub.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
|
@ -1,883 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
// This is the source code for the subprocess forked by the Simple
|
||||
// Windows Debug Server. It assumes most of the responsibility for the
|
||||
// debug session, and processes all of the commands sent by clients.
|
||||
|
||||
// Disable too-long symbol warnings
|
||||
#pragma warning ( disable : 4786 )
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
// Must come before windows.h
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include "IOBuf.hpp"
|
||||
#include "libInfo.hpp"
|
||||
#include "LockableList.hpp"
|
||||
#include "Message.hpp"
|
||||
#include "Monitor.hpp"
|
||||
#include "nt4internals.hpp"
|
||||
|
||||
// Uncomment the #define below to get messages on stderr
|
||||
// #define DEBUGGING
|
||||
|
||||
using namespace std;
|
||||
|
||||
DWORD pid;
|
||||
HANDLE procHandle;
|
||||
IOBuf* ioBuf;
|
||||
|
||||
// State flags indicating whether the attach to the remote process
|
||||
// definitively succeeded or failed
|
||||
volatile bool attachFailed = false;
|
||||
volatile bool attachSucceeded = false;
|
||||
|
||||
// State flag indicating whether the target process is suspended.
|
||||
// Modified by suspend()/resume(), viewed by debug thread, but only
|
||||
// under cover of the threads lock.
|
||||
volatile bool suspended = false;
|
||||
|
||||
// State flags indicating whether we are considered to be attached to
|
||||
// the target process and are therefore queuing up events to be sent
|
||||
// back to the debug server. These flags are only accessed and
|
||||
// modified under the cover of the eventLock.
|
||||
Monitor* eventLock;
|
||||
// The following is set to true when a client is attached to this process
|
||||
volatile bool generateDebugEvents = false;
|
||||
// Pointer to current debug event; non-NULL indicates a debug event is
|
||||
// waiting to be sent to the client. Main thread sets this to NULL to
|
||||
// indicate that the event has been consumed; also sets
|
||||
// passEventToClient, below.
|
||||
volatile DEBUG_EVENT* curDebugEvent = NULL;
|
||||
// Set by main thread to indicate whether the most recently posted
|
||||
// debug event should be passed on to the target process.
|
||||
volatile bool passEventToClient = true;
|
||||
|
||||
void conditionalPostDebugEvent(DEBUG_EVENT* ev, DWORD* continueOrNotHandledFlag) {
|
||||
// FIXME: make it possible for the client to enable and disable
|
||||
// certain types of events (have to do so in a platform-independent
|
||||
// manner)
|
||||
switch (ev->dwDebugEventCode) {
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
switch (ev->u.Exception.ExceptionRecord.ExceptionCode) {
|
||||
case EXCEPTION_BREAKPOINT: break;
|
||||
case EXCEPTION_SINGLE_STEP: break;
|
||||
case EXCEPTION_ACCESS_VIOLATION: break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
eventLock->lock();
|
||||
if (generateDebugEvents) {
|
||||
curDebugEvent = ev;
|
||||
while (curDebugEvent != NULL) {
|
||||
eventLock->wait();
|
||||
}
|
||||
if (passEventToClient) {
|
||||
*continueOrNotHandledFlag = DBG_EXCEPTION_NOT_HANDLED;
|
||||
} else {
|
||||
*continueOrNotHandledFlag = DBG_CONTINUE;
|
||||
}
|
||||
}
|
||||
eventLock->unlock();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Module list
|
||||
//
|
||||
|
||||
vector<LibInfo> libs;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Thread list
|
||||
//
|
||||
|
||||
struct ThreadInfo {
|
||||
DWORD tid;
|
||||
HANDLE thread;
|
||||
|
||||
ThreadInfo(DWORD tid, HANDLE thread) {
|
||||
this->tid = tid;
|
||||
this->thread = thread;
|
||||
}
|
||||
};
|
||||
|
||||
class ThreadList : public LockableList<ThreadInfo> {
|
||||
public:
|
||||
bool removeByThreadID(DWORD tid) {
|
||||
for (InternalListType::iterator iter = internalList.begin();
|
||||
iter != internalList.end(); iter++) {
|
||||
if ((*iter).tid == tid) {
|
||||
internalList.erase(iter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
HANDLE threadIDToHandle(DWORD tid) {
|
||||
for (InternalListType::iterator iter = internalList.begin();
|
||||
iter != internalList.end(); iter++) {
|
||||
if ((*iter).tid == tid) {
|
||||
return (*iter).thread;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
ThreadList threads;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// INITIALIZATION AND TERMINATION
|
||||
//
|
||||
|
||||
void
|
||||
printError(const char* prefix) {
|
||||
DWORD detail = GetLastError();
|
||||
LPTSTR message;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
0,
|
||||
detail,
|
||||
0,
|
||||
(LPTSTR) &message,
|
||||
1,
|
||||
NULL);
|
||||
// FIXME: This is signaling an error: "The handle is invalid." ?
|
||||
// Do I have to do all of my WaitForDebugEvent calls from the same thread?
|
||||
cerr << prefix << ": " << message << endl;
|
||||
LocalFree(message);
|
||||
}
|
||||
|
||||
void
|
||||
endProcess(bool waitForProcess = true) {
|
||||
NT4::unloadNTDLL();
|
||||
if (waitForProcess) {
|
||||
// Though we're exiting because of an error, do not tear down the
|
||||
// target process.
|
||||
WaitForSingleObject(procHandle, INFINITE);
|
||||
}
|
||||
CloseHandle(procHandle);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
debugThreadEntry(void*) {
|
||||
#ifdef DEBUGGING
|
||||
DWORD lastMsgId = 0;
|
||||
int count = 0;
|
||||
#endif
|
||||
|
||||
if (!DebugActiveProcess(pid)) {
|
||||
attachFailed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Wait for debug events. We keep the information from some of these
|
||||
// on the side in anticipation of later queries by the client. NOTE
|
||||
// that we leave the process running. The main thread is responsible
|
||||
// for suspending and resuming all currently-active threads upon
|
||||
// client attach and detach.
|
||||
|
||||
while (true) {
|
||||
DEBUG_EVENT ev;
|
||||
if (!WaitForDebugEvent(&ev, INFINITE)) {
|
||||
#ifdef DEBUGGING
|
||||
if (++count < 10) {
|
||||
// FIXME: This is signaling an error: "The handle is invalid." ?
|
||||
// Do I have to do all of my WaitForDebugEvent calls from the same thread?
|
||||
printError("WaitForDebugEvent failed");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
|
||||
#ifdef DEBUGGING
|
||||
if (ev.dwDebugEventCode != lastMsgId) {
|
||||
lastMsgId = ev.dwDebugEventCode;
|
||||
count = 0;
|
||||
cerr << "Debug thread received event " << ev.dwDebugEventCode << endl;
|
||||
} else {
|
||||
if (++count < 10) {
|
||||
cerr << "Debug thread received event " << ev.dwDebugEventCode << endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD dbgContinueMode = DBG_CONTINUE;
|
||||
|
||||
switch (ev.dwDebugEventCode) {
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
conditionalPostDebugEvent(&ev, &dbgContinueMode);
|
||||
break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
conditionalPostDebugEvent(&ev, &dbgContinueMode);
|
||||
break;
|
||||
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
threads.lock();
|
||||
// FIXME: will this deal properly with child processes? If
|
||||
// not, is it possible to make it do so?
|
||||
#ifdef DEBUGGING
|
||||
cerr << "CREATE_PROCESS_DEBUG_EVENT " << ev.dwThreadId
|
||||
<< " " << ev.u.CreateProcessInfo.hThread << endl;
|
||||
#endif
|
||||
if (ev.u.CreateProcessInfo.hThread != NULL) {
|
||||
threads.add(ThreadInfo(ev.dwThreadId, ev.u.CreateProcessInfo.hThread));
|
||||
}
|
||||
threads.unlock();
|
||||
break;
|
||||
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
threads.lock();
|
||||
#ifdef DEBUGGING
|
||||
cerr << "CREATE_THREAD_DEBUG_EVENT " << ev.dwThreadId
|
||||
<< " " << ev.u.CreateThread.hThread << endl;
|
||||
#endif
|
||||
if (suspended) {
|
||||
// Suspend this thread before adding it to the thread list
|
||||
SuspendThread(ev.u.CreateThread.hThread);
|
||||
}
|
||||
threads.add(ThreadInfo(ev.dwThreadId, ev.u.CreateThread.hThread));
|
||||
threads.unlock();
|
||||
break;
|
||||
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
threads.lock();
|
||||
#ifdef DEBUGGING
|
||||
cerr << "EXIT_THREAD_DEBUG_EVENT " << ev.dwThreadId << endl;
|
||||
#endif
|
||||
threads.removeByThreadID(ev.dwThreadId);
|
||||
threads.unlock();
|
||||
break;
|
||||
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
// cerr << "EXCEPTION_DEBUG_EVENT" << endl;
|
||||
switch (ev.u.Exception.ExceptionRecord.ExceptionCode) {
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
// cerr << "EXCEPTION_BREAKPOINT" << endl;
|
||||
if (!attachSucceeded && !attachFailed) {
|
||||
attachSucceeded = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dbgContinueMode = DBG_EXCEPTION_NOT_HANDLED;
|
||||
break;
|
||||
}
|
||||
conditionalPostDebugEvent(&ev, &dbgContinueMode);
|
||||
break;
|
||||
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
endProcess(false);
|
||||
// NOT REACHED
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Received debug event " << ev.dwDebugEventCode << endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, dbgContinueMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
attachToProcess() {
|
||||
// Create event lock
|
||||
eventLock = new Monitor();
|
||||
|
||||
// Get a process handle for later
|
||||
procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
||||
if (procHandle == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start up the debug thread
|
||||
DWORD debugThreadId;
|
||||
if (CreateThread(NULL, 0, &debugThreadEntry, NULL, 0, &debugThreadId) == NULL) {
|
||||
// Failed to make background debug thread. Fail.
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((!attachSucceeded) && (!attachFailed)) {
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
if (attachFailed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(attachSucceeded);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
readMessage(Message* msg) {
|
||||
DWORD numRead;
|
||||
if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE),
|
||||
msg,
|
||||
sizeof(Message),
|
||||
&numRead,
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (numRead != sizeof(Message)) {
|
||||
return false;
|
||||
}
|
||||
// For "poke" messages, must follow up by reading raw data
|
||||
if (msg->type == Message::POKE) {
|
||||
char* dataBuf = new char[msg->pokeArg.numBytes];
|
||||
if (dataBuf == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE),
|
||||
dataBuf,
|
||||
msg->pokeArg.numBytes,
|
||||
&numRead,
|
||||
NULL)) {
|
||||
delete[] dataBuf;
|
||||
return false;
|
||||
}
|
||||
if (numRead != msg->pokeArg.numBytes) {
|
||||
delete[] dataBuf;
|
||||
return false;
|
||||
}
|
||||
msg->pokeArg.data = (void *) dataBuf;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
handlePeek(Message* msg) {
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Entering handlePeek()" << endl;
|
||||
#endif
|
||||
|
||||
char* memBuf = new char[msg->peekArg.numBytes];
|
||||
if (memBuf == NULL) {
|
||||
ioBuf->writeString("B");
|
||||
ioBuf->writeBinChar(0);
|
||||
ioBuf->flush();
|
||||
delete[] memBuf;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try fast case first
|
||||
DWORD numRead;
|
||||
BOOL res = ReadProcessMemory(procHandle,
|
||||
(LPCVOID) msg->peekArg.address,
|
||||
memBuf,
|
||||
msg->peekArg.numBytes,
|
||||
&numRead);
|
||||
if (res && (numRead == msg->peekArg.numBytes)) {
|
||||
|
||||
// OK, complete success. Phew.
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Peek success case" << endl;
|
||||
#endif
|
||||
ioBuf->writeString("B");
|
||||
ioBuf->writeBinChar(1);
|
||||
ioBuf->writeBinUnsignedInt(numRead);
|
||||
ioBuf->writeBinChar(1);
|
||||
ioBuf->writeBinBuf(memBuf, numRead);
|
||||
} else {
|
||||
#ifdef DEBUGGING
|
||||
cerr << "*** Peek slow case ***" << endl;
|
||||
#endif
|
||||
|
||||
ioBuf->writeString("B");
|
||||
ioBuf->writeBinChar(1);
|
||||
|
||||
// Use VirtualQuery to speed things up a bit
|
||||
DWORD numLeft = msg->peekArg.numBytes;
|
||||
char* curAddr = (char*) msg->peekArg.address;
|
||||
while (numLeft > 0) {
|
||||
MEMORY_BASIC_INFORMATION memInfo;
|
||||
VirtualQueryEx(procHandle, curAddr, &memInfo, sizeof(memInfo));
|
||||
DWORD numToRead = memInfo.RegionSize;
|
||||
if (numToRead > numLeft) {
|
||||
numToRead = numLeft;
|
||||
}
|
||||
DWORD numRead;
|
||||
if (memInfo.State == MEM_COMMIT) {
|
||||
// Read the process memory at this address for this length
|
||||
// FIXME: should check the result of this read
|
||||
ReadProcessMemory(procHandle, curAddr, memBuf,
|
||||
numToRead, &numRead);
|
||||
// Write this out
|
||||
#ifdef DEBUGGING
|
||||
cerr << "*** Writing " << numToRead << " bytes as mapped ***" << endl;
|
||||
#endif
|
||||
ioBuf->writeBinUnsignedInt(numToRead);
|
||||
ioBuf->writeBinChar(1);
|
||||
ioBuf->writeBinBuf(memBuf, numToRead);
|
||||
} else {
|
||||
// Indicate region is free
|
||||
#ifdef DEBUGGING
|
||||
cerr << "*** Writing " << numToRead << " bytes as unmapped ***" << endl;
|
||||
#endif
|
||||
ioBuf->writeBinUnsignedInt(numToRead);
|
||||
ioBuf->writeBinChar(0);
|
||||
}
|
||||
curAddr += numToRead;
|
||||
numLeft -= numToRead;
|
||||
}
|
||||
}
|
||||
|
||||
ioBuf->flush();
|
||||
delete[] memBuf;
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Exiting handlePeek()" << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
handlePoke(Message* msg) {
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Entering handlePoke()" << endl;
|
||||
#endif
|
||||
DWORD numWritten;
|
||||
BOOL res = WriteProcessMemory(procHandle,
|
||||
(LPVOID) msg->pokeArg.address,
|
||||
msg->pokeArg.data,
|
||||
msg->pokeArg.numBytes,
|
||||
&numWritten);
|
||||
if (res && (numWritten == msg->pokeArg.numBytes)) {
|
||||
// Success
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
#ifdef DEBUGGING
|
||||
cerr << " (Succeeded)" << endl;
|
||||
#endif
|
||||
} else {
|
||||
// Failure
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
#ifdef DEBUGGING
|
||||
cerr << " (Failed)" << endl;
|
||||
#endif
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
// We clean up the data
|
||||
char* dataBuf = (char*) msg->pokeArg.data;
|
||||
delete[] dataBuf;
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Exiting handlePoke()" << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
suspend() {
|
||||
if (suspended) {
|
||||
return false;
|
||||
}
|
||||
// Before we suspend, we must take a snapshot of the loaded module
|
||||
// names and base addresses, since acquiring this snapshot requires
|
||||
// starting and exiting a thread in the remote process (at least on
|
||||
// NT 4).
|
||||
libs.clear();
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Starting suspension" << endl;
|
||||
#endif
|
||||
libInfo(pid, libs);
|
||||
#ifdef DEBUGGING
|
||||
cerr << " Got lib info" << endl;
|
||||
#endif
|
||||
threads.lock();
|
||||
#ifdef DEBUGGING
|
||||
cerr << " Got thread lock" << endl;
|
||||
#endif
|
||||
suspended = true;
|
||||
int j = 0;
|
||||
for (int i = 0; i < threads.size(); i++) {
|
||||
j++;
|
||||
SuspendThread(threads.get(i).thread);
|
||||
}
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Suspended " << j << " threads" << endl;
|
||||
#endif
|
||||
threads.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
resume() {
|
||||
if (!suspended) {
|
||||
return false;
|
||||
}
|
||||
threads.lock();
|
||||
suspended = false;
|
||||
for (int i = 0; i < threads.size(); i++) {
|
||||
ResumeThread(threads.get(i).thread);
|
||||
}
|
||||
threads.unlock();
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Resumed process" << endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
// Should only be used by performing CreateProcess within SwDbgSrv
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sscanf(argv[1], "%u", &pid) != 1) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Try to attach to process
|
||||
if (!attachToProcess()) {
|
||||
// Attach failed. Notify parent by writing result to stdout file
|
||||
// handle.
|
||||
char res = 0;
|
||||
DWORD numBytes;
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &res, sizeof(res),
|
||||
&numBytes, NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Server is expecting success result back.
|
||||
char res = 1;
|
||||
DWORD numBytes;
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &res, sizeof(res),
|
||||
&numBytes, NULL);
|
||||
|
||||
// Initialize our I/O buffer
|
||||
ioBuf = new IOBuf(32768, 131072);
|
||||
ioBuf->setOutputFileHandle(GetStdHandle(STD_OUTPUT_HANDLE));
|
||||
|
||||
// At this point we are attached. Enter our main loop which services
|
||||
// requests from the server. Note that in order to handle attach/
|
||||
// detach properly (i.e., resumption of process upon "detach") we
|
||||
// will need another thread which handles debug events.
|
||||
while (true) {
|
||||
// Read a message from the server
|
||||
Message msg;
|
||||
if (!readMessage(&msg)) {
|
||||
endProcess();
|
||||
}
|
||||
|
||||
#ifdef DEBUGGING
|
||||
cerr << "Main thread read message: " << msg.type << endl;
|
||||
#endif
|
||||
|
||||
switch (msg.type) {
|
||||
// ATTACH and DETACH messages MUST come in pairs
|
||||
case Message::ATTACH:
|
||||
suspend();
|
||||
eventLock->lock();
|
||||
generateDebugEvents = true;
|
||||
eventLock->unlock();
|
||||
break;
|
||||
|
||||
case Message::DETACH:
|
||||
eventLock->lock();
|
||||
generateDebugEvents = false;
|
||||
// Flush remaining event if any
|
||||
if (curDebugEvent != NULL) {
|
||||
curDebugEvent = NULL;
|
||||
eventLock->notifyAll();
|
||||
}
|
||||
eventLock->unlock();
|
||||
resume();
|
||||
break;
|
||||
|
||||
case Message::LIBINFO:
|
||||
{
|
||||
if (!suspended) {
|
||||
ioBuf->writeInt(0);
|
||||
} else {
|
||||
// Send back formatted text
|
||||
ioBuf->writeInt(libs.size());
|
||||
for (int i = 0; i < libs.size(); i++) {
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeInt(1);
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeInt(libs[i].name.size());
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeString(libs[i].name.c_str());
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress(libs[i].base);
|
||||
}
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::PEEK:
|
||||
handlePeek(&msg);
|
||||
break;
|
||||
|
||||
case Message::POKE:
|
||||
handlePoke(&msg);
|
||||
break;
|
||||
|
||||
case Message::THREADLIST:
|
||||
{
|
||||
if (!suspended) {
|
||||
ioBuf->writeInt(0);
|
||||
} else {
|
||||
threads.lock();
|
||||
ioBuf->writeInt(threads.size());
|
||||
for (int i = 0; i < threads.size(); i++) {
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress((void*) threads.get(i).thread);
|
||||
}
|
||||
threads.unlock();
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::DUPHANDLE:
|
||||
{
|
||||
HANDLE dup;
|
||||
if (DuplicateHandle(procHandle,
|
||||
msg.handleArg.handle,
|
||||
GetCurrentProcess(),
|
||||
&dup,
|
||||
0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress((void*) dup);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::CLOSEHANDLE:
|
||||
{
|
||||
CloseHandle(msg.handleArg.handle);
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::GETCONTEXT:
|
||||
{
|
||||
if (!suspended) {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
} else {
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
|
||||
if (GetThreadContext(msg.handleArg.handle, &context)) {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
// EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EIP, DS, ES, FS, GS,
|
||||
// CS, SS, EFLAGS, DR0, DR1, DR2, DR3, DR6, DR7
|
||||
// See README-commands.txt
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Eax);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ebx);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ecx);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Edx);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Esi);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Edi);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ebp);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Esp);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Eip);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegDs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegEs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegFs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegGs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegCs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegSs);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.EFlags);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr0);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr1);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr2);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr3);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr6);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr7);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
}
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::SETCONTEXT:
|
||||
{
|
||||
if (!suspended) {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
} else {
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
|
||||
context.Eax = msg.setContextArg.Eax;
|
||||
context.Ebx = msg.setContextArg.Ebx;
|
||||
context.Ecx = msg.setContextArg.Ecx;
|
||||
context.Edx = msg.setContextArg.Edx;
|
||||
context.Esi = msg.setContextArg.Esi;
|
||||
context.Edi = msg.setContextArg.Edi;
|
||||
context.Ebp = msg.setContextArg.Ebp;
|
||||
context.Esp = msg.setContextArg.Esp;
|
||||
context.Eip = msg.setContextArg.Eip;
|
||||
context.SegDs = msg.setContextArg.Ds;
|
||||
context.SegEs = msg.setContextArg.Es;
|
||||
context.SegFs = msg.setContextArg.Fs;
|
||||
context.SegGs = msg.setContextArg.Gs;
|
||||
context.SegCs = msg.setContextArg.Cs;
|
||||
context.SegSs = msg.setContextArg.Ss;
|
||||
context.EFlags = msg.setContextArg.EFlags;
|
||||
context.Dr0 = msg.setContextArg.Dr0;
|
||||
context.Dr1 = msg.setContextArg.Dr1;
|
||||
context.Dr2 = msg.setContextArg.Dr2;
|
||||
context.Dr3 = msg.setContextArg.Dr3;
|
||||
context.Dr6 = msg.setContextArg.Dr6;
|
||||
context.Dr7 = msg.setContextArg.Dr7;
|
||||
if (SetThreadContext(msg.setContextArg.handle, &context)) {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
}
|
||||
}
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::SELECTORENTRY:
|
||||
{
|
||||
LDT_ENTRY entry;
|
||||
|
||||
if (GetThreadSelectorEntry(msg.selectorArg.handle,
|
||||
msg.selectorArg.selector,
|
||||
&entry)) {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.LimitLow);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.BaseLow);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.BaseMid);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.Flags1);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.Flags2);
|
||||
ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.BaseHi);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
}
|
||||
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case Message::SUSPEND:
|
||||
suspend();
|
||||
break;
|
||||
|
||||
case Message::RESUME:
|
||||
resume();
|
||||
break;
|
||||
|
||||
case Message::POLLEVENT:
|
||||
eventLock->lock();
|
||||
if (curDebugEvent == NULL) {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
} else {
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
ioBuf->writeSpace();
|
||||
threads.lock();
|
||||
ioBuf->writeAddress((void*) threads.threadIDToHandle(curDebugEvent->dwThreadId));
|
||||
threads.unlock();
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeUnsignedInt(curDebugEvent->dwDebugEventCode);
|
||||
// Figure out what else to write
|
||||
switch (curDebugEvent->dwDebugEventCode) {
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress(curDebugEvent->u.LoadDll.lpBaseOfDll);
|
||||
break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress(curDebugEvent->u.UnloadDll.lpBaseOfDll);
|
||||
break;
|
||||
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
{
|
||||
DWORD code = curDebugEvent->u.Exception.ExceptionRecord.ExceptionCode;
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeUnsignedInt(code);
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress(curDebugEvent->u.Exception.ExceptionRecord.ExceptionAddress);
|
||||
switch (curDebugEvent->u.Exception.ExceptionRecord.ExceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeBoolAsInt(curDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0] != 0);
|
||||
ioBuf->writeSpace();
|
||||
ioBuf->writeAddress((void*) curDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
eventLock->unlock();
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
|
||||
case Message::CONTINUEEVENT:
|
||||
eventLock->lock();
|
||||
if (curDebugEvent == NULL) {
|
||||
ioBuf->writeBoolAsInt(false);
|
||||
} else {
|
||||
curDebugEvent = NULL;
|
||||
passEventToClient = msg.boolArg.val;
|
||||
ioBuf->writeBoolAsInt(true);
|
||||
eventLock->notify();
|
||||
}
|
||||
eventLock->unlock();
|
||||
ioBuf->writeEOL();
|
||||
ioBuf->flush();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endProcess();
|
||||
|
||||
// NOT REACHED
|
||||
return 0;
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
# Microsoft Developer Studio Project File - Name="SwDbgSub" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=SwDbgSub - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "SwDbgSub.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "SwDbgSub.mak" CFG="SwDbgSub - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "SwDbgSub - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "SwDbgSub - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "SwDbgSub - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "SwDbgSub - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "SwDbgSub___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "SwDbgSub___Win32_Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "SwDbgSub - Win32 Release"
|
||||
# Name "SwDbgSub - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Buffer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IOBuf.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\isNT4.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\libInfo.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Monitor.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\nt4internals.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\SwDbgSub.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\toolHelp.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <winsock2.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void
|
||||
initWinsock()
|
||||
{
|
||||
static int initted = 0;
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
int err;
|
||||
|
||||
if (!initted) {
|
||||
wVersionRequested = MAKEWORD( 2, 0 );
|
||||
|
||||
err = WSAStartup( wVersionRequested, &wsaData );
|
||||
if ( err != 0 ) {
|
||||
{
|
||||
/* Tell the user that we couldn't find a usable */
|
||||
/* WinSock DLL. */
|
||||
cerr << "SocketBase::SocketBase: unable to find usable "
|
||||
<< "WinSock DLL" << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Confirm that the WinSock DLL supports 2.0.*/
|
||||
/* Note that if the DLL supports versions greater */
|
||||
/* than 2.0 in addition to 2.0, it will still return */
|
||||
/* 2.0 in wVersion since that is the version we */
|
||||
/* requested. */
|
||||
|
||||
if ( LOBYTE( wsaData.wVersion ) != 2 ||
|
||||
HIBYTE( wsaData.wVersion ) != 0 ) {
|
||||
/* Tell the user that we couldn't find a usable */
|
||||
/* WinSock DLL. */
|
||||
{
|
||||
cerr << "Unable to find suitable version of WinSock DLL" << endl;
|
||||
WSACleanup( );
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
initted = 1;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _INIT_WINSOCK_
|
||||
#define _INIT_WINSOCK_
|
||||
|
||||
void initWinsock();
|
||||
|
||||
#endif // #defined _INIT_WINSOCK_
|
|
@ -1,156 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "ioUtils.hpp"
|
||||
#include "IOBuf.hpp"
|
||||
|
||||
bool
|
||||
scanInt(char** data, int* num) {
|
||||
*num = 0;
|
||||
|
||||
// Skip whitespace
|
||||
while ((**data != 0) && (isspace(**data))) {
|
||||
++*data;
|
||||
}
|
||||
|
||||
if (**data == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((**data != 0) && (!isspace(**data))) {
|
||||
char cur = **data;
|
||||
if ((cur < '0') || (cur > '9')) {
|
||||
return false;
|
||||
}
|
||||
*num *= 10;
|
||||
*num += cur - '0';
|
||||
++*data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
scanUnsignedLong(char** data, unsigned long* num) {
|
||||
*num = 0;
|
||||
|
||||
// Skip whitespace
|
||||
while ((**data != 0) && (isspace(**data))) {
|
||||
++*data;
|
||||
}
|
||||
|
||||
if (**data == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((**data != 0) && (!isspace(**data))) {
|
||||
char cur = **data;
|
||||
if ((cur < '0') || (cur > '9')) {
|
||||
return false;
|
||||
}
|
||||
*num *= 10;
|
||||
*num += cur - '0';
|
||||
++*data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
charToNibble(char ascii, int* value) {
|
||||
if (ascii >= '0' && ascii <= '9') {
|
||||
*value = ascii - '0';
|
||||
return true;
|
||||
} else if (ascii >= 'A' && ascii <= 'F') {
|
||||
*value = 10 + ascii - 'A';
|
||||
return true;
|
||||
} else if (ascii >= 'a' && ascii <= 'f') {
|
||||
*value = 10 + ascii - 'a';
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
scanAddress(char** data, unsigned long* addr) {
|
||||
*addr = 0;
|
||||
|
||||
// Skip whitespace
|
||||
while ((**data != 0) && (isspace(**data))) {
|
||||
++*data;
|
||||
}
|
||||
|
||||
if (**data == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncmp(*data, "0x", 2) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*data += 2;
|
||||
|
||||
while ((**data != 0) && (!isspace(**data))) {
|
||||
int val;
|
||||
bool res = charToNibble(**data, &val);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
*addr <<= 4;
|
||||
*addr |= val;
|
||||
++*data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
scanAndSkipBinEscapeChar(char** data) {
|
||||
// Skip whitespace
|
||||
while ((**data != 0) && (isspace(**data))) {
|
||||
++*data;
|
||||
}
|
||||
|
||||
if (!IOBuf::isBinEscapeChar(**data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++*data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
scanBinUnsignedLong(char** data, unsigned long* num) {
|
||||
*num = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
unsigned char val = (unsigned char) **data;
|
||||
*num = (*num << 8) | val;
|
||||
++*data;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IO_UTILS_
|
||||
#define _IO_UTILS_
|
||||
|
||||
bool scanInt(char** data, int* num);
|
||||
bool scanUnsignedLong(char** data, unsigned long* num);
|
||||
bool scanAddress(char** data, unsigned long* addr);
|
||||
|
||||
// Binary utils (for poke)
|
||||
bool scanAndSkipBinEscapeChar(char** data);
|
||||
bool scanBinUnsignedLong(char** data, unsigned long* num);
|
||||
|
||||
#endif // #defined _IO_UTILS_
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "isNT4.hpp"
|
||||
#include <windows.h>
|
||||
|
||||
bool
|
||||
isNT4() {
|
||||
OSVERSIONINFO info;
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
|
||||
if (!GetVersionEx(&info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((info.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
|
||||
(info.dwMajorVersion == 4));
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ISNT4_H_
|
||||
#define _ISNT4_H_
|
||||
|
||||
// We need to special-case the Windows NT 4.0 implementations of some
|
||||
// of the debugging routines because the Tool Help API is not
|
||||
// available on this platform.
|
||||
|
||||
bool isNT4();
|
||||
|
||||
#endif // #defined _ISNT4_H_
|
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
// Disable too-long symbol warnings
|
||||
#pragma warning ( disable : 4786 )
|
||||
|
||||
#include "libInfo.hpp"
|
||||
#include "nt4internals.hpp"
|
||||
#include "isNT4.hpp"
|
||||
#include "toolHelp.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef void LibInfoImplFunc(DWORD pid, vector<LibInfo>& info);
|
||||
|
||||
static void libInfoImplNT4(DWORD pid, vector<LibInfo>& info);
|
||||
static void libInfoImplToolHelp(DWORD pid, vector<LibInfo>& info);
|
||||
|
||||
void
|
||||
libInfo(DWORD pid, vector<LibInfo>& info) {
|
||||
static LibInfoImplFunc* impl = NULL;
|
||||
|
||||
if (impl == NULL) {
|
||||
// See which operating system we're on
|
||||
impl = (isNT4() ? &libInfoImplNT4 : &libInfoImplToolHelp);
|
||||
}
|
||||
|
||||
assert(impl != NULL);
|
||||
|
||||
(*impl)(pid, info);
|
||||
}
|
||||
|
||||
static ULONG
|
||||
ModuleCount(NT4::PDEBUG_BUFFER db) {
|
||||
return db->ModuleInformation ? *PULONG(db->ModuleInformation) : 0;
|
||||
}
|
||||
|
||||
#define MAX2(a, b) (((a) < (b)) ? (b) : (a))
|
||||
|
||||
static void
|
||||
libInfoImplNT4(DWORD pid, vector<LibInfo>& info) {
|
||||
static EnumProcessModulesFunc* enumFunc = NULL;
|
||||
static GetModuleFileNameExFunc* fnFunc = NULL;
|
||||
static GetModuleInformationFunc* infoFunc = NULL;
|
||||
|
||||
if (enumFunc == NULL) {
|
||||
HMODULE dll = loadPSAPIDLL();
|
||||
|
||||
enumFunc = (EnumProcessModulesFunc*) GetProcAddress(dll, "EnumProcessModules");
|
||||
fnFunc = (GetModuleFileNameExFunc*) GetProcAddress(dll, "GetModuleFileNameExA");
|
||||
infoFunc = (GetModuleInformationFunc*) GetProcAddress(dll, "GetModuleInformation");
|
||||
|
||||
assert(enumFunc != NULL);
|
||||
assert(fnFunc != NULL);
|
||||
assert(infoFunc != NULL);
|
||||
}
|
||||
|
||||
static HMODULE* mods = new HMODULE[256];
|
||||
static int numMods = 256;
|
||||
|
||||
if (mods == NULL) {
|
||||
mods = new HMODULE[numMods];
|
||||
if (mods == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
|
||||
HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
||||
if (proc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
DWORD bufSize = numMods * sizeof(HMODULE);
|
||||
DWORD neededSize;
|
||||
|
||||
if (!(*enumFunc)(proc, mods, bufSize, &neededSize)) {
|
||||
// Enum failed
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
|
||||
int numFetched = neededSize / sizeof(HMODULE);
|
||||
|
||||
if (numMods < numFetched) {
|
||||
// Grow buffer
|
||||
numMods = MAX2(numFetched, 2 * numMods);
|
||||
delete[] mods;
|
||||
mods = new HMODULE[numMods];
|
||||
if (mods == NULL) {
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
char filename[MAX_PATH];
|
||||
MODULEINFO modInfo;
|
||||
|
||||
// Iterate through and fetch each one's info
|
||||
for (int i = 0; i < numFetched; i++) {
|
||||
if (!(*fnFunc)(proc, mods[i], filename, MAX_PATH)) {
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(*infoFunc)(proc, mods[i], &modInfo, sizeof(MODULEINFO))) {
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
|
||||
info.push_back(LibInfo(string(filename), (void*) modInfo.lpBaseOfDll));
|
||||
}
|
||||
|
||||
done = true;
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
CloseHandle(proc);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
libInfoImplToolHelp(DWORD pid, vector<LibInfo>& info) {
|
||||
using namespace ToolHelp;
|
||||
|
||||
static CreateToolhelp32SnapshotFunc* snapshotFunc = NULL;
|
||||
static Module32FirstFunc* firstFunc = NULL;
|
||||
static Module32NextFunc* nextFunc = NULL;
|
||||
|
||||
if (snapshotFunc == NULL) {
|
||||
HMODULE dll = loadDLL();
|
||||
|
||||
snapshotFunc =
|
||||
(CreateToolhelp32SnapshotFunc*) GetProcAddress(dll,
|
||||
"CreateToolhelp32Snapshot");
|
||||
|
||||
firstFunc = (Module32FirstFunc*) GetProcAddress(dll,
|
||||
"Module32First");
|
||||
|
||||
nextFunc = (Module32NextFunc*) GetProcAddress(dll,
|
||||
"Module32Next");
|
||||
|
||||
assert(snapshotFunc != NULL);
|
||||
assert(firstFunc != NULL);
|
||||
assert(nextFunc != NULL);
|
||||
}
|
||||
|
||||
HANDLE snapshot = (*snapshotFunc)(TH32CS_SNAPMODULE, pid);
|
||||
if (snapshot == (HANDLE) -1) {
|
||||
// Error occurred during snapshot
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate
|
||||
MODULEENTRY32 module;
|
||||
if ((*firstFunc)(snapshot, &module)) {
|
||||
do {
|
||||
info.push_back(LibInfo(string(module.szExePath), (void*) module.modBaseAddr));
|
||||
} while ((*nextFunc)(snapshot, &module));
|
||||
}
|
||||
|
||||
CloseHandle(snapshot);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBINFO_
|
||||
#define _LIBINFO_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <windows.h>
|
||||
|
||||
struct LibInfo {
|
||||
std::string name;
|
||||
void* base;
|
||||
|
||||
LibInfo(const std::string& name, void* base) {
|
||||
this->name = name;
|
||||
this->base = base;
|
||||
}
|
||||
};
|
||||
|
||||
void libInfo(DWORD pid, std::vector<LibInfo>& info);
|
||||
|
||||
#endif // #defined _LIBINFO_
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nt4internals.hpp"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace NT4 {
|
||||
|
||||
static HMODULE ntDLL = NULL;
|
||||
|
||||
HMODULE loadNTDLL() {
|
||||
if (ntDLL == NULL) {
|
||||
ntDLL = LoadLibrary("NTDLL.DLL");
|
||||
}
|
||||
|
||||
assert(ntDLL != NULL);
|
||||
return ntDLL;
|
||||
}
|
||||
|
||||
void unloadNTDLL() {
|
||||
if (ntDLL != NULL) {
|
||||
FreeLibrary(ntDLL);
|
||||
ntDLL = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace NT4
|
||||
|
||||
static HMODULE psapiDLL = NULL;
|
||||
|
||||
HMODULE
|
||||
loadPSAPIDLL() {
|
||||
if (psapiDLL == NULL) {
|
||||
psapiDLL = LoadLibrary("PSAPI.DLL");
|
||||
}
|
||||
|
||||
if (psapiDLL == NULL) {
|
||||
fprintf(stderr, "Simple Windows Debug Server requires PSAPI.DLL on Windows NT 4.0.\n");
|
||||
fprintf(stderr, "Please install this DLL from the SDK and restart the server.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return psapiDLL;
|
||||
}
|
||||
|
||||
void
|
||||
unloadPSAPIDLL() {
|
||||
if (psapiDLL != NULL) {
|
||||
FreeLibrary(psapiDLL);
|
||||
psapiDLL = NULL;
|
||||
}
|
||||
}
|
|
@ -1,273 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NT4INTERNALS_H_
|
||||
#define _NT4INTERNALS_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace NT4 {
|
||||
extern "C" {
|
||||
|
||||
// Data structures and constants required to be able to get necessary
|
||||
// debugging-related information on Windows NT 4.0 through internal
|
||||
// (i.e., non-public) APIs. These are adapted from those in the
|
||||
// _Windows NT/2000 Native API Reference_ by Gary Nebbett, Macmillan
|
||||
// Technical Publishing, 201 West 103rd Street, Indianapolis, IN
|
||||
// 46290, 2000.
|
||||
|
||||
typedef LONG NTSTATUS;
|
||||
typedef LONG KPRIORITY;
|
||||
|
||||
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
|
||||
#define NTAPI __stdcall
|
||||
#else
|
||||
#define _cdecl
|
||||
#define NTAPI
|
||||
#endif
|
||||
|
||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
|
||||
|
||||
typedef enum _SYSTEM_INFORMATION_CLASS {
|
||||
SystemProcessesAndThreadsInformation = 5
|
||||
} SYSTEM_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING;
|
||||
|
||||
typedef struct _VM_COUNTERS {
|
||||
ULONG PeakVirtualSize;
|
||||
ULONG VirtualSize;
|
||||
ULONG PageFaultCount;
|
||||
ULONG PeakWorkingSetSize;
|
||||
ULONG WorkingSetSize;
|
||||
ULONG QuotaPeakPagedPoolUsage;
|
||||
ULONG QuotaPagedPoolUsage;
|
||||
ULONG QuotaPeakNonPagedPoolUsage;
|
||||
ULONG QuotaNonPagedPoolUsage;
|
||||
ULONG PagefileUsage;
|
||||
ULONG PeakPagefileUsage;
|
||||
} VM_COUNTERS, *PVM_COUNTERS;
|
||||
|
||||
typedef struct _IO_COUNTERS {
|
||||
LARGE_INTEGER ReadOperationCount;
|
||||
LARGE_INTEGER WriteOperationCount;
|
||||
LARGE_INTEGER OtherOperationCount;
|
||||
LARGE_INTEGER ReadTransferCount;
|
||||
LARGE_INTEGER WriteTransferCount;
|
||||
LARGE_INTEGER OtherTransferCount;
|
||||
} IO_COUNTERS, *PIO_COUNTERS;
|
||||
|
||||
typedef struct _CLIENT_ID {
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID, *PCLIENT_ID;
|
||||
|
||||
typedef enum {
|
||||
StateInitialized,
|
||||
StateReady,
|
||||
StateRunning,
|
||||
StateStandby,
|
||||
StateTerminated,
|
||||
StateWait,
|
||||
StateTransition,
|
||||
StateUnknown
|
||||
} THREAD_STATE;
|
||||
|
||||
typedef enum {
|
||||
Executive,
|
||||
FreePage,
|
||||
PageIn,
|
||||
PoolAllocation,
|
||||
DelayExecution,
|
||||
Suspended,
|
||||
UserRequest,
|
||||
WrExecutive,
|
||||
WrFreePage,
|
||||
WrPageIn,
|
||||
WrPoolAllocation,
|
||||
WrDelayExecution,
|
||||
WrSuspended,
|
||||
WrUserRequest,
|
||||
WrEventPair,
|
||||
WrQueue,
|
||||
WrLpcReceive,
|
||||
WrLpcReply,
|
||||
WrVirtualMemory,
|
||||
WrPageOut,
|
||||
WrRendezvous,
|
||||
Spare2,
|
||||
Spare3,
|
||||
Spare4,
|
||||
Spare5,
|
||||
Spare6,
|
||||
WrKernel
|
||||
} KWAIT_REASON;
|
||||
|
||||
typedef struct _SYSTEM_THREADS {
|
||||
LARGE_INTEGER KernelTime;
|
||||
LARGE_INTEGER UserTime;
|
||||
LARGE_INTEGER CreateTime;
|
||||
ULONG WaitTime;
|
||||
PVOID StartAddress;
|
||||
CLIENT_ID ClientId;
|
||||
KPRIORITY Priority;
|
||||
KPRIORITY BasePriority;
|
||||
ULONG ContextSwitchCount;
|
||||
THREAD_STATE State;
|
||||
KWAIT_REASON WaitReason;
|
||||
} SYSTEM_THREADS, *PSYSTEM_THREADS;
|
||||
|
||||
typedef struct _SYSTEM_PROCESSES { // Information class 5
|
||||
ULONG NextEntryDelta;
|
||||
ULONG ThreadCount;
|
||||
ULONG Reserved1[6];
|
||||
LARGE_INTEGER CreateTime;
|
||||
LARGE_INTEGER UserTime;
|
||||
LARGE_INTEGER KernelTime;
|
||||
UNICODE_STRING ProcessName;
|
||||
KPRIORITY BasePriority;
|
||||
ULONG ProcessId;
|
||||
ULONG InheritedFromProcessId;
|
||||
ULONG HandleCount;
|
||||
ULONG Reserved2[2];
|
||||
ULONG PrivatePageCount;
|
||||
VM_COUNTERS VmCounters;
|
||||
IO_COUNTERS IoCounters; // Windows 2000 only
|
||||
SYSTEM_THREADS Threads[1];
|
||||
} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
|
||||
|
||||
typedef NTSTATUS NTAPI
|
||||
ZwQuerySystemInformationFunc(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
IN OUT PVOID SystemInformation,
|
||||
IN ULONG SystemInformationLength,
|
||||
OUT PULONG ReturnLength OPTIONAL
|
||||
);
|
||||
|
||||
typedef struct _DEBUG_BUFFER {
|
||||
HANDLE SectionHandle;
|
||||
PVOID SectionBase;
|
||||
PVOID RemoteSectionBase;
|
||||
ULONG SectionBaseDelta;
|
||||
HANDLE EventPairHandle;
|
||||
ULONG Unknown[2];
|
||||
HANDLE RemoteThreadHandle;
|
||||
ULONG InfoClassMask;
|
||||
ULONG SizeOfInfo;
|
||||
ULONG AllocatedSize;
|
||||
ULONG SectionSize;
|
||||
PVOID ModuleInformation;
|
||||
PVOID BackTraceInformation;
|
||||
PVOID HeapInformation;
|
||||
PVOID LockInformation;
|
||||
PVOID Reserved[8];
|
||||
} DEBUG_BUFFER, *PDEBUG_BUFFER;
|
||||
|
||||
typedef PDEBUG_BUFFER NTAPI
|
||||
RtlCreateQueryDebugBufferFunc(IN ULONG Size,
|
||||
IN BOOLEAN EventPair);
|
||||
|
||||
#define PDI_MODULES 0x01 // The loaded modules of the process
|
||||
#define PDI_BACKTRACE 0x02 // The heap stack back traces
|
||||
#define PDI_HEAPS 0x04 // The heaps of the process
|
||||
#define PDI_HEAP_TAGS 0x08 // The heap tags
|
||||
#define PDI_HEAP_BLOCKS 0x10 // The heap blocks
|
||||
#define PDI_LOCKS 0x20 // The locks created by the process
|
||||
|
||||
typedef struct _DEBUG_MODULE_INFORMATION { // c.f. SYSTEM_MODULE_INFORMATION
|
||||
ULONG Reserved[2];
|
||||
ULONG Base;
|
||||
ULONG Size;
|
||||
ULONG Flags;
|
||||
USHORT Index;
|
||||
USHORT Unknown;
|
||||
USHORT LoadCount;
|
||||
USHORT ModuleNameOffset;
|
||||
CHAR ImageName[256];
|
||||
} DEBUG_MODULE_INFORMATION, *PDEBUG_MODULE_INFORMATION;
|
||||
|
||||
// Flags
|
||||
#define LDRP_STATIC_LINK 0x00000002
|
||||
#define LDRP_IMAGE_DLL 0x00000004
|
||||
#define LDRP_LOAD_IN_PROGRESS 0x00001000
|
||||
#define LDRP_UNLOAD_IN_PROGRESS 0x00002000
|
||||
#define LDRP_ENTRY_PROCESSED 0x00004000
|
||||
#define LDRP_ENTRY_INSERTED 0x00008000
|
||||
#define LDRP_CURRENT_LOAD 0x00010000
|
||||
#define LDRP_FAILED_BUILTIN_LOAD 0x00020000
|
||||
#define LDRP_DONT_CALL_FOR_THREADS 0x00040000
|
||||
#define LDRP_PROCESS_ATTACH_CALLED 0x00080000
|
||||
#define LDRP_DEBUG_SYMBOLS_LOADED 0x00100000
|
||||
#define LDRP_IMAGE_NOT_AT_BASE 0x00200000
|
||||
#define LDRP_WX86_IGNORE_MACHINETYPE 0x00400000
|
||||
|
||||
// NOTE that this will require creating a thread in the target
|
||||
// process, implying that we can not call this while the process is
|
||||
// suspended. May have to run this command in the child processes
|
||||
// rather than the server.
|
||||
|
||||
typedef NTSTATUS NTAPI
|
||||
RtlQueryProcessDebugInformationFunc(IN ULONG ProcessId,
|
||||
IN ULONG DebugInfoClassMask,
|
||||
IN OUT PDEBUG_BUFFER DebugBuffer);
|
||||
|
||||
typedef NTSTATUS NTAPI
|
||||
RtlDestroyQueryDebugBufferFunc(IN PDEBUG_BUFFER DebugBuffer);
|
||||
|
||||
// Routines to load and unload NTDLL.DLL.
|
||||
HMODULE loadNTDLL();
|
||||
// Safe to call even if has not been loaded
|
||||
void unloadNTDLL();
|
||||
|
||||
} // extern "C"
|
||||
} // namespace NT4
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// On NT 4 only, we now use PSAPI to enumerate the loaded modules in
|
||||
// the target processes. RtlQueryProcessDebugInformation creates a
|
||||
// thread in the target process, which causes problems when we are
|
||||
// handling events like breakpoints in the debugger. The dependence on
|
||||
// an external DLL which might not be present is unfortunate, but we
|
||||
// can either redistribute this DLL (if allowed) or refuse to start on
|
||||
// NT 4 if it is not present.
|
||||
|
||||
typedef struct _MODULEINFO {
|
||||
LPVOID lpBaseOfDll;
|
||||
DWORD SizeOfImage;
|
||||
LPVOID EntryPoint;
|
||||
} MODULEINFO, *LPMODULEINFO;
|
||||
|
||||
typedef BOOL (WINAPI EnumProcessModulesFunc)(HANDLE, HMODULE *, DWORD, LPDWORD);
|
||||
typedef DWORD (WINAPI GetModuleFileNameExFunc)(HANDLE, HMODULE, LPTSTR, DWORD);
|
||||
typedef BOOL (WINAPI GetModuleInformationFunc)(HANDLE, HMODULE, LPMODULEINFO, DWORD);
|
||||
// Routines to load and unload PSAPI.DLL.
|
||||
HMODULE loadPSAPIDLL();
|
||||
// Safe to call even if has not been loaded
|
||||
void unloadPSAPIDLL();
|
||||
|
||||
#endif // #defined _NT4INTERNALS_H_
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PORTS_H_
|
||||
#define _PORTS_H_
|
||||
|
||||
// This is the "public" port which end-user clients can connect to
|
||||
// with an arbitrary application, including telnet.
|
||||
const short CLIENT_PORT = 27000;
|
||||
|
||||
#endif // #defined _PORTS_H_
|
|
@ -1,190 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "procList.hpp"
|
||||
#include "nt4internals.hpp"
|
||||
#include "isNT4.hpp"
|
||||
#include "toolHelp.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace NT4;
|
||||
|
||||
typedef void ProcListImplFunc(ProcEntryList& processes);
|
||||
|
||||
void procListImplNT4(ProcEntryList& processes);
|
||||
void procListImplToolHelp(ProcEntryList& processes);
|
||||
|
||||
ProcEntry::ProcEntry(ULONG pid, USHORT nameLength, WCHAR* name) {
|
||||
this->pid = pid;
|
||||
this->nameLength = nameLength;
|
||||
this->name = new WCHAR[nameLength];
|
||||
memcpy(this->name, name, nameLength * sizeof(WCHAR));
|
||||
}
|
||||
|
||||
ProcEntry::ProcEntry(ULONG pid, USHORT nameLength, char* name) {
|
||||
this->pid = pid;
|
||||
this->nameLength = nameLength;
|
||||
this->name = new WCHAR[nameLength];
|
||||
int j = 0;
|
||||
for (int i = 0; i < nameLength; i++) {
|
||||
// FIXME: what is the proper promotion from ASCII to UNICODE?
|
||||
this->name[i] = name[i] & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
ProcEntry::ProcEntry(const ProcEntry& arg) {
|
||||
name = NULL;
|
||||
copyFrom(arg);
|
||||
}
|
||||
|
||||
ProcEntry&
|
||||
ProcEntry::operator=(const ProcEntry& arg) {
|
||||
copyFrom(arg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProcEntry::~ProcEntry() {
|
||||
delete[] name;
|
||||
}
|
||||
|
||||
void
|
||||
ProcEntry::copyFrom(const ProcEntry& arg) {
|
||||
if (name != NULL) {
|
||||
delete[] name;
|
||||
}
|
||||
pid = arg.pid;
|
||||
nameLength = arg.nameLength;
|
||||
name = new WCHAR[nameLength];
|
||||
memcpy(name, arg.name, nameLength * sizeof(WCHAR));
|
||||
}
|
||||
|
||||
ULONG
|
||||
ProcEntry::getPid() {
|
||||
return pid;
|
||||
}
|
||||
|
||||
USHORT
|
||||
ProcEntry::getNameLength() {
|
||||
return nameLength;
|
||||
}
|
||||
|
||||
WCHAR*
|
||||
ProcEntry::getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
procList(ProcEntryList& processes) {
|
||||
static ProcListImplFunc* impl = NULL;
|
||||
|
||||
if (impl == NULL) {
|
||||
// See which operating system we're on
|
||||
impl = (isNT4() ? &procListImplNT4 : &procListImplToolHelp);
|
||||
}
|
||||
|
||||
assert(impl != NULL);
|
||||
|
||||
(*impl)(processes);
|
||||
}
|
||||
|
||||
void
|
||||
procListImplNT4(ProcEntryList& processes) {
|
||||
using namespace NT4;
|
||||
|
||||
static ZwQuerySystemInformationFunc* query = NULL;
|
||||
|
||||
if (query == NULL) {
|
||||
HMODULE ntDLL = loadNTDLL();
|
||||
query =
|
||||
(ZwQuerySystemInformationFunc*) GetProcAddress(ntDLL,
|
||||
"ZwQuerySystemInformation");
|
||||
assert(query != NULL);
|
||||
}
|
||||
|
||||
ULONG n = 0x100;
|
||||
PSYSTEM_PROCESSES sp = new SYSTEM_PROCESSES[n];
|
||||
while ((*query)(SystemProcessesAndThreadsInformation,
|
||||
sp, n * sizeof(SYSTEM_PROCESSES), 0) == STATUS_INFO_LENGTH_MISMATCH) {
|
||||
delete[] sp;
|
||||
n *= 2;
|
||||
sp = new SYSTEM_PROCESSES[n];
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
for (PSYSTEM_PROCESSES p = sp; !done;
|
||||
p = PSYSTEM_PROCESSES(PCHAR(p) + p->NextEntryDelta)) {
|
||||
processes.push_back(ProcEntry(p->ProcessId,
|
||||
p->ProcessName.Length / 2,
|
||||
p->ProcessName.Buffer));
|
||||
done = p->NextEntryDelta == 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
procListImplToolHelp(ProcEntryList& processes) {
|
||||
using namespace ToolHelp;
|
||||
|
||||
static CreateToolhelp32SnapshotFunc* snapshotFunc = NULL;
|
||||
static Process32FirstFunc* firstFunc = NULL;
|
||||
static Process32NextFunc* nextFunc = NULL;
|
||||
|
||||
if (snapshotFunc == NULL) {
|
||||
HMODULE dll = loadDLL();
|
||||
|
||||
snapshotFunc =
|
||||
(CreateToolhelp32SnapshotFunc*) GetProcAddress(dll,
|
||||
"CreateToolhelp32Snapshot");
|
||||
|
||||
firstFunc = (Process32FirstFunc*) GetProcAddress(dll,
|
||||
"Process32First");
|
||||
|
||||
nextFunc = (Process32NextFunc*) GetProcAddress(dll,
|
||||
"Process32Next");
|
||||
|
||||
assert(snapshotFunc != NULL);
|
||||
assert(firstFunc != NULL);
|
||||
assert(nextFunc != NULL);
|
||||
}
|
||||
|
||||
HANDLE snapshot = (*snapshotFunc)(TH32CS_SNAPPROCESS, 0 /* ignored */);
|
||||
if (snapshot == (HANDLE) -1) {
|
||||
// Error occurred during snapshot
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate
|
||||
PROCESSENTRY32 proc;
|
||||
if ((*firstFunc)(snapshot, &proc)) {
|
||||
do {
|
||||
// FIXME: could make this uniform to the NT version by cutting
|
||||
// off the path name just before the executable name
|
||||
processes.push_back(ProcEntry(proc.th32ProcessID,
|
||||
strlen(proc.szExeFile),
|
||||
proc.szExeFile));
|
||||
} while ((*nextFunc)(snapshot, &proc));
|
||||
}
|
||||
|
||||
CloseHandle(snapshot);
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PROCLIST_
|
||||
#define _PROCLIST_
|
||||
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
|
||||
class ProcEntry {
|
||||
public:
|
||||
/** name may not be NULL */
|
||||
ProcEntry(ULONG pid, USHORT nameLength, wchar_t* name);
|
||||
ProcEntry(ULONG pid, USHORT nameLength, char* name);
|
||||
~ProcEntry();
|
||||
ProcEntry(const ProcEntry& arg);
|
||||
ProcEntry& operator=(const ProcEntry& arg);
|
||||
|
||||
ULONG getPid();
|
||||
/** Returns number of WCHAR characters in getName() */
|
||||
USHORT getNameLength();
|
||||
WCHAR* getName();
|
||||
|
||||
private:
|
||||
ULONG pid;
|
||||
USHORT nameLength;
|
||||
WCHAR* name;
|
||||
void copyFrom(const ProcEntry& arg);
|
||||
};
|
||||
|
||||
typedef std::vector<ProcEntry> ProcEntryList;
|
||||
void procList(ProcEntryList& processes);
|
||||
|
||||
#endif // #defined _PROCLIST_
|
|
@ -1,270 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "serverLists.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Lists
|
||||
//
|
||||
|
||||
CRITICAL_SECTION Lists::crit;
|
||||
|
||||
void
|
||||
Lists::init() {
|
||||
InitializeCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void
|
||||
Lists::lock() {
|
||||
EnterCriticalSection(&crit);
|
||||
}
|
||||
|
||||
void
|
||||
Lists::unlock() {
|
||||
LeaveCriticalSection(&crit);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ListsLocker
|
||||
//
|
||||
|
||||
ListsLocker::ListsLocker() {
|
||||
Lists::lock();
|
||||
}
|
||||
|
||||
ListsLocker::~ListsLocker() {
|
||||
Lists::unlock();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ChildInfo
|
||||
//
|
||||
|
||||
ChildInfo::ChildInfo(DWORD pid, HANDLE childProcessHandle,
|
||||
HANDLE writeToStdinHandle, HANDLE readFromStdoutHandle,
|
||||
HANDLE auxHandle1, HANDLE auxHandle2) {
|
||||
this->pid = pid;
|
||||
this->childProcessHandle = childProcessHandle;
|
||||
this->writeToStdinHandle = writeToStdinHandle;
|
||||
this->readFromStdoutHandle = readFromStdoutHandle;
|
||||
this->auxHandle1 = auxHandle1;
|
||||
this->auxHandle2 = auxHandle2;
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
DWORD
|
||||
ChildInfo::getPid() {
|
||||
return pid;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
ChildInfo::getChildProcessHandle() {
|
||||
return childProcessHandle;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
ChildInfo::getWriteToStdinHandle() {
|
||||
return writeToStdinHandle;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
ChildInfo::getReadFromStdoutHandle() {
|
||||
return readFromStdoutHandle;
|
||||
}
|
||||
|
||||
void
|
||||
ChildInfo::setClient(ClientInfo* clientInfo) {
|
||||
client = clientInfo;
|
||||
}
|
||||
|
||||
ClientInfo*
|
||||
ChildInfo::getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
void
|
||||
ChildInfo::closeAll() {
|
||||
CloseHandle(childProcessHandle);
|
||||
CloseHandle(writeToStdinHandle);
|
||||
CloseHandle(readFromStdoutHandle);
|
||||
CloseHandle(auxHandle1);
|
||||
CloseHandle(auxHandle2);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ChildList
|
||||
//
|
||||
|
||||
ChildList::ChildList() {
|
||||
}
|
||||
|
||||
ChildList::~ChildList() {
|
||||
}
|
||||
|
||||
void
|
||||
ChildList::addChild(ChildInfo* info) {
|
||||
// Could store these in binary sorted order by pid for efficiency
|
||||
childList.push_back(info);
|
||||
}
|
||||
|
||||
ChildInfo*
|
||||
ChildList::removeChild(HANDLE childProcessHandle) {
|
||||
for (ChildInfoList::iterator iter = childList.begin(); iter != childList.end();
|
||||
iter++) {
|
||||
ChildInfo* info = *iter;
|
||||
if (info->getChildProcessHandle() == childProcessHandle) {
|
||||
childList.erase(iter);
|
||||
return info;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ChildList::removeChild(ChildInfo* info) {
|
||||
for (ChildInfoList::iterator iter = childList.begin(); iter != childList.end();
|
||||
iter++) {
|
||||
if (*iter == info) {
|
||||
childList.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
ChildInfo*
|
||||
ChildList::getChildByPid(DWORD pid) {
|
||||
for (ChildInfoList::iterator iter = childList.begin(); iter != childList.end();
|
||||
iter++) {
|
||||
ChildInfo* info = *iter;
|
||||
if (info->getPid() == pid) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
ChildList::size() {
|
||||
return childList.size();
|
||||
}
|
||||
|
||||
ChildInfo*
|
||||
ChildList::getChildByIndex(int index) {
|
||||
return childList[index];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ClientInfo
|
||||
//
|
||||
|
||||
ClientInfo::ClientInfo(SOCKET dataSocket) {
|
||||
this->dataSocket = dataSocket;
|
||||
buf = new IOBuf(32768, 131072);
|
||||
buf->setSocket(dataSocket);
|
||||
target = NULL;
|
||||
}
|
||||
|
||||
ClientInfo::~ClientInfo() {
|
||||
delete buf;
|
||||
}
|
||||
|
||||
SOCKET
|
||||
ClientInfo::getDataSocket() {
|
||||
return dataSocket;
|
||||
}
|
||||
|
||||
IOBuf*
|
||||
ClientInfo::getIOBuf() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
ClientInfo::setTarget(ChildInfo* childInfo) {
|
||||
target = childInfo;
|
||||
}
|
||||
|
||||
ChildInfo*
|
||||
ClientInfo::getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
void
|
||||
ClientInfo::closeAll() {
|
||||
shutdown(dataSocket, SD_BOTH);
|
||||
closesocket(dataSocket);
|
||||
dataSocket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ClientList
|
||||
//
|
||||
|
||||
ClientList::ClientList() {
|
||||
}
|
||||
|
||||
ClientList::~ClientList() {
|
||||
}
|
||||
|
||||
void
|
||||
ClientList::addClient(ClientInfo* info) {
|
||||
clientList.push_back(info);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientList::isAnyDataSocketSet(fd_set* fds, ClientInfo** out) {
|
||||
for (ClientInfoList::iterator iter = clientList.begin(); iter != clientList.end();
|
||||
iter++) {
|
||||
ClientInfo* info = *iter;
|
||||
if (FD_ISSET(info->getDataSocket(), fds)) {
|
||||
*out = info;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ClientList::removeClient(ClientInfo* client) {
|
||||
for (ClientInfoList::iterator iter = clientList.begin(); iter != clientList.end();
|
||||
iter++) {
|
||||
if (*iter == client) {
|
||||
clientList.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
int
|
||||
ClientList::size() {
|
||||
return clientList.size();
|
||||
}
|
||||
|
||||
ClientInfo*
|
||||
ClientList::get(int num) {
|
||||
return clientList[num];
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SERVER_LISTS_
|
||||
#define _SERVER_LISTS_
|
||||
|
||||
#include <vector>
|
||||
#include <winsock2.h>
|
||||
#include "IOBuf.hpp"
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
//
|
||||
// All of these lists are guarded by the global lock managed by the
|
||||
// Lists class. Lists::init() must be called at the start of the
|
||||
// program.
|
||||
//
|
||||
|
||||
class Lists {
|
||||
friend class ListsLocker;
|
||||
public:
|
||||
static void init();
|
||||
private:
|
||||
static void lock();
|
||||
static void unlock();
|
||||
static CRITICAL_SECTION crit;
|
||||
};
|
||||
|
||||
// Should be allocated on stack. Ensures proper locking/unlocking
|
||||
// pairing.
|
||||
class ListsLocker {
|
||||
public:
|
||||
ListsLocker();
|
||||
~ListsLocker();
|
||||
};
|
||||
|
||||
// We must keep track of all of the child processes we have forked to
|
||||
// handle attaching to a target process. This is necessary because we
|
||||
// allow clients to detach from processes, but the child processes we
|
||||
// fork must necessarily stay alive for the duration of the target
|
||||
// application. A subsequent attach operation to the target process
|
||||
// results in the same child process being reused. For this reason,
|
||||
// child processes are known to be in one of two states: attached and
|
||||
// detached.
|
||||
|
||||
class ClientInfo;
|
||||
|
||||
class ChildInfo {
|
||||
public:
|
||||
/** The pid of the ChildInfo indicates the process ID of the target
|
||||
process which the subprocess was created to debug, not the pid
|
||||
of the subprocess itself. */
|
||||
ChildInfo(DWORD pid, HANDLE childProcessHandle,
|
||||
HANDLE writeToStdinHandle, HANDLE readFromStdoutHandle,
|
||||
HANDLE auxHandle1, HANDLE auxHandle2);
|
||||
|
||||
DWORD getPid();
|
||||
HANDLE getChildProcessHandle();
|
||||
HANDLE getWriteToStdinHandle();
|
||||
HANDLE getReadFromStdoutHandle();
|
||||
|
||||
/** Set the client which is currently attached to the target process
|
||||
via this child process. Set this to NULL to indicate that the
|
||||
child process is ready to accept another attachment. */
|
||||
void setClient(ClientInfo* clientInfo);
|
||||
|
||||
ClientInfo* getClient();
|
||||
|
||||
/** This is NOT automatically called in the destructor */
|
||||
void closeAll();
|
||||
|
||||
private:
|
||||
DWORD pid;
|
||||
HANDLE childProcessHandle;
|
||||
HANDLE writeToStdinHandle;
|
||||
HANDLE readFromStdoutHandle;
|
||||
HANDLE auxHandle1;
|
||||
HANDLE auxHandle2;
|
||||
ClientInfo* client;
|
||||
};
|
||||
|
||||
// We keep track of a list of child debugger processes, each of which
|
||||
// is responsible for debugging a certain target process. These
|
||||
// debugger processes can serve multiple clients during their
|
||||
// lifetime. When a client detaches from a given process or tells the
|
||||
// debugger to "exit", the debug server is notified that the child
|
||||
// process is once again available to accept connections from clients.
|
||||
|
||||
class ChildList {
|
||||
private:
|
||||
typedef std::vector<ChildInfo*> ChildInfoList;
|
||||
|
||||
public:
|
||||
ChildList();
|
||||
~ChildList();
|
||||
|
||||
void addChild(ChildInfo*);
|
||||
|
||||
/** Removes and returns the ChildInfo* associated with the given
|
||||
child process handle. */
|
||||
ChildInfo* removeChild(HANDLE childProcessHandle);
|
||||
|
||||
/** Removes the given ChildInfo. */
|
||||
void removeChild(ChildInfo* info);
|
||||
|
||||
/** Return the ChildInfo* associated with a given process ID without
|
||||
removing it from the list. */
|
||||
ChildInfo* getChildByPid(DWORD pid);
|
||||
|
||||
/** Iteration support */
|
||||
int size();
|
||||
|
||||
/** Iteration support */
|
||||
ChildInfo* getChildByIndex(int index);
|
||||
|
||||
private:
|
||||
ChildInfoList childList;
|
||||
};
|
||||
|
||||
// We also keep a list of clients whose requests we are responsible
|
||||
// for serving. Clients can attach and detach from child processes.
|
||||
|
||||
class ClientInfo {
|
||||
public:
|
||||
ClientInfo(SOCKET dataSocket);
|
||||
~ClientInfo();
|
||||
|
||||
SOCKET getDataSocket();
|
||||
/** Gets an IOBuf configured for the data socket, which should be
|
||||
used for all communication with the client. */
|
||||
IOBuf* getIOBuf();
|
||||
|
||||
/** Set the information for the process to which this client is
|
||||
attached. Set this to NULL to indicate that the client is not
|
||||
currently attached to any target process. */
|
||||
void setTarget(ChildInfo* childInfo);
|
||||
|
||||
/** Get the information for the process to which this client is
|
||||
currently attached, or NULL if none. */
|
||||
ChildInfo* getTarget();
|
||||
|
||||
/** Close down the socket connection to this client. This is NOT
|
||||
automatically called by the destructor. */
|
||||
void closeAll();
|
||||
|
||||
private:
|
||||
SOCKET dataSocket;
|
||||
IOBuf* buf;
|
||||
ChildInfo* target;
|
||||
};
|
||||
|
||||
class ClientList {
|
||||
private:
|
||||
typedef std::vector<ClientInfo*> ClientInfoList;
|
||||
|
||||
public:
|
||||
ClientList();
|
||||
~ClientList();
|
||||
|
||||
/** Adds a client to the list. */
|
||||
void addClient(ClientInfo* info);
|
||||
|
||||
/** Check to see whether the parent socket of any of the ClientInfo
|
||||
objects is readable in the given fd_set. If so, returns TRUE and
|
||||
sets the given ClientInfo* (a non-NULL pointer to which must be
|
||||
given) appropriately. */
|
||||
bool isAnyDataSocketSet(fd_set* fds, ClientInfo** info);
|
||||
|
||||
/** Removes a client from the list. User is responsible for deleting
|
||||
the ClientInfo* using operator delete. */
|
||||
void removeClient(ClientInfo* client);
|
||||
|
||||
/** Iteration support. */
|
||||
int size();
|
||||
|
||||
/** Iteration support. */
|
||||
ClientInfo* get(int num);
|
||||
|
||||
private:
|
||||
ClientInfoList clientList;
|
||||
};
|
||||
|
||||
#endif // #defined _SERVER_LISTS_
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "toolHelp.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
namespace ToolHelp {
|
||||
|
||||
static HMODULE kernelDLL = NULL;
|
||||
|
||||
HMODULE loadDLL() {
|
||||
if (kernelDLL == NULL) {
|
||||
kernelDLL = LoadLibrary("KERNEL32.DLL");
|
||||
}
|
||||
|
||||
assert(kernelDLL != NULL);
|
||||
return kernelDLL;
|
||||
}
|
||||
|
||||
void unloadDLL() {
|
||||
if (kernelDLL != NULL) {
|
||||
FreeLibrary(kernelDLL);
|
||||
kernelDLL = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ToolHelp
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TOOLHELP_H_
|
||||
#define _TOOLHELP_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
namespace ToolHelp {
|
||||
extern "C" {
|
||||
|
||||
///////////////
|
||||
// Snapshots //
|
||||
///////////////
|
||||
typedef HANDLE WINAPI
|
||||
CreateToolhelp32SnapshotFunc(DWORD dwFlags, DWORD th32ProcessID);
|
||||
|
||||
//////////////////
|
||||
// Process List //
|
||||
//////////////////
|
||||
typedef BOOL WINAPI Process32FirstFunc(HANDLE hSnapshot,
|
||||
LPPROCESSENTRY32 lppe);
|
||||
|
||||
typedef BOOL WINAPI Process32NextFunc(HANDLE hSnapshot,
|
||||
LPPROCESSENTRY32 lppe);
|
||||
|
||||
// NOTE: although these routines are defined in TLHELP32.H, they
|
||||
// seem to always return false (maybe only under US locales)
|
||||
typedef BOOL WINAPI Process32FirstWFunc(HANDLE hSnapshot,
|
||||
LPPROCESSENTRY32W lppe);
|
||||
|
||||
typedef BOOL WINAPI Process32NextWFunc(HANDLE hSnapshot,
|
||||
LPPROCESSENTRY32W lppe);
|
||||
|
||||
/////////////////
|
||||
// Module List //
|
||||
/////////////////
|
||||
typedef BOOL WINAPI
|
||||
Module32FirstFunc(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
|
||||
|
||||
typedef BOOL WINAPI
|
||||
Module32NextFunc (HANDLE hSnapshot, LPMODULEENTRY32 lpme);
|
||||
|
||||
|
||||
// Routines to load and unload KERNEL32.DLL.
|
||||
HMODULE loadDLL();
|
||||
// Safe to call even if has not been loaded
|
||||
void unloadDLL();
|
||||
|
||||
} // extern "C"
|
||||
} // namespace "ToolHelp"
|
||||
|
||||
#endif // #defined _TOOLHELP_H_
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
import sun.jvm.hotspot.types.basic.*;
|
||||
|
||||
public class BsdVtblAccess extends BasicVtblAccess {
|
||||
private String vt;
|
||||
|
||||
public BsdVtblAccess(SymbolLookup symbolLookup,
|
||||
String[] dllNames) {
|
||||
super(symbolLookup, dllNames);
|
||||
|
||||
if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null ||
|
||||
symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) {
|
||||
// old C++ ABI
|
||||
vt = "__vt_";
|
||||
} else {
|
||||
// new C++ ABI
|
||||
vt = "_ZTV";
|
||||
}
|
||||
}
|
||||
|
||||
protected String vtblSymbolForType(Type type) {
|
||||
return vt + type.getName().length() + type;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -170,6 +170,7 @@ public class CLHSDB {
|
|||
final String errMsg = formatMessage(e.getMessage(), 80);
|
||||
System.err.println("Unable to connect to process ID " + pid + ":\n\n" + errMsg);
|
||||
agent.detach();
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +192,7 @@ public class CLHSDB {
|
|||
final String errMsg = formatMessage(e.getMessage(), 80);
|
||||
System.err.println("Unable to open core file\n" + corePath + ":\n\n" + errMsg);
|
||||
agent.detach();
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +211,7 @@ public class CLHSDB {
|
|||
final String errMsg = formatMessage(e.getMessage(), 80);
|
||||
System.err.println("Unable to connect to machine \"" + remoteMachineName + "\":\n\n" + errMsg);
|
||||
agent.detach();
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ import sun.jvm.hotspot.debugger.*;
|
|||
import sun.jvm.hotspot.interpreter.*;
|
||||
import sun.jvm.hotspot.memory.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
import sun.jvm.hotspot.opto.*;
|
||||
import sun.jvm.hotspot.ci.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.utilities.*;
|
||||
import sun.jvm.hotspot.utilities.soql.*;
|
||||
|
@ -48,6 +50,8 @@ import sun.jvm.hotspot.ui.tree.*;
|
|||
import sun.jvm.hotspot.tools.*;
|
||||
import sun.jvm.hotspot.tools.ObjectHistogram;
|
||||
import sun.jvm.hotspot.tools.StackTrace;
|
||||
import sun.jvm.hotspot.tools.jcore.ClassDump;
|
||||
import sun.jvm.hotspot.tools.jcore.ClassFilter;
|
||||
|
||||
public class CommandProcessor {
|
||||
public abstract static class DebuggerInterface {
|
||||
|
@ -59,6 +63,27 @@ public class CommandProcessor {
|
|||
public abstract void reattach();
|
||||
}
|
||||
|
||||
public static class BootFilter implements ClassFilter {
|
||||
public boolean canInclude(InstanceKlass kls) {
|
||||
return kls.getClassLoader() == null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NonBootFilter implements ClassFilter {
|
||||
private HashMap emitted = new HashMap();
|
||||
public boolean canInclude(InstanceKlass kls) {
|
||||
if (kls.getClassLoader() == null) return false;
|
||||
if (emitted.get(kls.getName()) != null) {
|
||||
// Since multiple class loaders are being shoved
|
||||
// together duplicate classes are a possibilty. For
|
||||
// now just ignore them.
|
||||
return false;
|
||||
}
|
||||
emitted.put(kls.getName(), kls);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class Tokens {
|
||||
final String input;
|
||||
int i;
|
||||
|
@ -258,9 +283,14 @@ public class CommandProcessor {
|
|||
}
|
||||
|
||||
void dumpFields(Type type) {
|
||||
dumpFields(type, true);
|
||||
}
|
||||
|
||||
void dumpFields(Type type, boolean allowStatic) {
|
||||
Iterator i = type.getFields();
|
||||
while (i.hasNext()) {
|
||||
Field f = (Field) i.next();
|
||||
if (!allowStatic && f.isStatic()) continue;
|
||||
out.print("field ");
|
||||
quote(type.getName());
|
||||
out.print(" ");
|
||||
|
@ -458,13 +488,18 @@ public class CommandProcessor {
|
|||
});
|
||||
}
|
||||
},
|
||||
new Command("flags", "flags [ flag ]", false) {
|
||||
new Command("flags", "flags [ flag | -nd ]", false) {
|
||||
public void doit(Tokens t) {
|
||||
int tokens = t.countTokens();
|
||||
if (tokens != 0 && tokens != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String name = tokens > 0 ? t.nextToken() : null;
|
||||
boolean nonDefault = false;
|
||||
if (name != null && name.equals("-nd")) {
|
||||
name = null;
|
||||
nonDefault = true;
|
||||
}
|
||||
|
||||
VM.Flag[] flags = VM.getVM().getCommandLineFlags();
|
||||
if (flags == null) {
|
||||
|
@ -474,7 +509,12 @@ public class CommandProcessor {
|
|||
for (int f = 0; f < flags.length; f++) {
|
||||
VM.Flag flag = flags[f];
|
||||
if (name == null || flag.getName().equals(name)) {
|
||||
out.println(flag.getName() + " = " + flag.getValue());
|
||||
|
||||
if (nonDefault && flag.getOrigin() == 0) {
|
||||
// only print flags which aren't their defaults
|
||||
continue;
|
||||
}
|
||||
out.println(flag.getName() + " = " + flag.getValue() + " " + flag.getOrigin());
|
||||
printed = true;
|
||||
}
|
||||
}
|
||||
|
@ -586,6 +626,158 @@ public class CommandProcessor {
|
|||
}
|
||||
}
|
||||
},
|
||||
new Command("printmdo", "printmdo [ -a | expression ]", false) {
|
||||
// Print every MDO in the heap or the one referenced by expression.
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String s = t.nextToken();
|
||||
if (s.equals("-a")) {
|
||||
HeapVisitor iterator = new DefaultHeapVisitor() {
|
||||
public boolean doObj(Oop obj) {
|
||||
if (obj instanceof MethodData) {
|
||||
Method m = ((MethodData)obj).getMethod();
|
||||
out.println("MethodData " + obj.getHandle() + " for " +
|
||||
"method " + m.getMethodHolder().getName().asString() + "." +
|
||||
m.getName().asString() +
|
||||
m.getSignature().asString() + "@" + m.getHandle());
|
||||
((MethodData)obj).printDataOn(out);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
VM.getVM().getObjectHeap().iteratePerm(iterator);
|
||||
} else {
|
||||
Address a = VM.getVM().getDebugger().parseAddress(s);
|
||||
OopHandle handle = a.addOffsetToAsOopHandle(0);
|
||||
MethodData mdo = (MethodData)VM.getVM().getObjectHeap().newOop(handle);
|
||||
mdo.printDataOn(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("dumpideal", "dumpideal { -a | id }", false) {
|
||||
// Do a full dump of the nodes reachabile from root in each compiler thread.
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String name = t.nextToken();
|
||||
boolean all = name.equals("-a");
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
thread.printThreadIDOn(new PrintStream(bos));
|
||||
if (all || bos.toString().equals(name)) {
|
||||
if (thread instanceof CompilerThread) {
|
||||
CompilerThread ct = (CompilerThread)thread;
|
||||
out.println(ct);
|
||||
ciEnv env = ct.env();
|
||||
if (env != null) {
|
||||
Compile c = env.compilerData();
|
||||
c.root().dump(9999, out);
|
||||
} else {
|
||||
out.println(" not compiling");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("dumpcfg", "dumpcfg { -a | id }", false) {
|
||||
// Dump the PhaseCFG for every compiler thread that has one live.
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String name = t.nextToken();
|
||||
boolean all = name.equals("-a");
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
thread.printThreadIDOn(new PrintStream(bos));
|
||||
if (all || bos.toString().equals(name)) {
|
||||
if (thread instanceof CompilerThread) {
|
||||
CompilerThread ct = (CompilerThread)thread;
|
||||
out.println(ct);
|
||||
ciEnv env = ct.env();
|
||||
if (env != null) {
|
||||
Compile c = env.compilerData();
|
||||
c.cfg().dump(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("dumpilt", "dumpilt { -a | id }", false) {
|
||||
// dumps the InlineTree of a C2 compile
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
} else {
|
||||
String name = t.nextToken();
|
||||
boolean all = name.equals("-a");
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
thread.printThreadIDOn(new PrintStream(bos));
|
||||
if (all || bos.toString().equals(name)) {
|
||||
if (thread instanceof CompilerThread) {
|
||||
CompilerThread ct = (CompilerThread)thread;
|
||||
ciEnv env = ct.env();
|
||||
if (env != null) {
|
||||
Compile c = env.compilerData();
|
||||
InlineTree ilt = c.ilt();
|
||||
if (ilt != null) {
|
||||
ilt.print(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("vmstructsdump", "vmstructsdump", false) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 0) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
// Dump a copy of the type database in a form that can
|
||||
// be read back.
|
||||
Iterator i = agent.getTypeDataBase().getTypes();
|
||||
// Make sure the types are emitted in an order than can be read back in
|
||||
HashSet emitted = new HashSet();
|
||||
Stack pending = new Stack();
|
||||
while (i.hasNext()) {
|
||||
Type n = (Type)i.next();
|
||||
if (emitted.contains(n.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (n != null && !emitted.contains(n.getName())) {
|
||||
pending.push(n);
|
||||
n = n.getSuperclass();
|
||||
}
|
||||
while (!pending.empty()) {
|
||||
n = (Type)pending.pop();
|
||||
dumpType(n);
|
||||
emitted.add(n.getName());
|
||||
}
|
||||
}
|
||||
i = agent.getTypeDataBase().getTypes();
|
||||
while (i.hasNext()) {
|
||||
dumpFields((Type)i.next(), false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
new Command("inspect", "inspect expression", false) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
|
@ -760,6 +952,50 @@ public class CommandProcessor {
|
|||
}
|
||||
}
|
||||
},
|
||||
new Command("intConstant", "intConstant [ name [ value ] ]", true) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
||||
if (t.countTokens() == 1) {
|
||||
out.println("intConstant " + name + " " + db.lookupIntConstant(name));
|
||||
} else if (t.countTokens() == 0) {
|
||||
Iterator i = db.getIntConstants();
|
||||
while (i.hasNext()) {
|
||||
String name = (String)i.next();
|
||||
out.println("intConstant " + name + " " + db.lookupIntConstant(name));
|
||||
}
|
||||
} else if (t.countTokens() == 2) {
|
||||
String name = t.nextToken();
|
||||
Integer value = Integer.valueOf(t.nextToken());
|
||||
db.addIntConstant(name, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("longConstant", "longConstant [ name [ value ] ]", true) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
||||
if (t.countTokens() == 1) {
|
||||
out.println("longConstant " + name + " " + db.lookupLongConstant(name));
|
||||
} else if (t.countTokens() == 0) {
|
||||
Iterator i = db.getLongConstants();
|
||||
while (i.hasNext()) {
|
||||
String name = (String)i.next();
|
||||
out.println("longConstant " + name + " " + db.lookupLongConstant(name));
|
||||
}
|
||||
} else if (t.countTokens() == 2) {
|
||||
String name = t.nextToken();
|
||||
Long value = Long.valueOf(t.nextToken());
|
||||
db.addLongConstant(name, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) {
|
||||
|
@ -1028,7 +1264,12 @@ public class CommandProcessor {
|
|||
if (AddressOps.equal(val, value)) {
|
||||
if (!printed) {
|
||||
printed = true;
|
||||
blob.printOn(out);
|
||||
try {
|
||||
blob.printOn(out);
|
||||
} catch (Exception e) {
|
||||
out.println("Exception printing blob at " + base);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
out.println("found at " + base + "\n");
|
||||
}
|
||||
|
@ -1306,13 +1547,13 @@ public class CommandProcessor {
|
|||
return;
|
||||
}
|
||||
|
||||
executeCommand(ln);
|
||||
executeCommand(ln, prompt);
|
||||
}
|
||||
}
|
||||
|
||||
static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*)|(![a-zA-Z][^ ]*))");
|
||||
|
||||
public void executeCommand(String ln) {
|
||||
public void executeCommand(String ln, boolean putInHistory) {
|
||||
if (ln.indexOf('!') != -1) {
|
||||
int size = history.size();
|
||||
if (size == 0) {
|
||||
|
@ -1401,7 +1642,7 @@ public class CommandProcessor {
|
|||
Tokens t = new Tokens(ln);
|
||||
if (t.hasMoreTokens()) {
|
||||
boolean error = false;
|
||||
history.add(ln);
|
||||
if (putInHistory) history.add(ln);
|
||||
int len = t.countTokens();
|
||||
if (len > 2) {
|
||||
String r = t.at(len - 2);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -25,7 +25,6 @@
|
|||
package sun.jvm.hotspot;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.dbx.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.oops.*;
|
||||
|
||||
|
|
|
@ -1740,7 +1740,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
|||
else if (f.isCompiledFrame()) { tty.print("compiled"); }
|
||||
else if (f.isEntryFrame()) { tty.print("entry"); }
|
||||
else if (f.isNativeFrame()) { tty.print("native"); }
|
||||
else if (f.isGlueFrame()) { tty.print("glue"); }
|
||||
else if (f.isRuntimeFrame()) { tty.print("runtime"); }
|
||||
else { tty.print("external"); }
|
||||
tty.print(" frame with PC = " + f.getPC() + ", SP = " + f.getSP() + ", FP = " + f.getFP());
|
||||
if (f.isSignalHandlerFrameDbg()) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue