Index: /trunk/COPYING.LIB
===================================================================
--- /trunk/COPYING.LIB	(revision 2)
+++ /trunk/COPYING.LIB	(revision 2)
@@ -0,0 +1,513 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
Index: /trunk/Config.kmk
===================================================================
--- /trunk/Config.kmk	(revision 2)
+++ /trunk/Config.kmk	(revision 2)
@@ -0,0 +1,130 @@
+# $Id$
+## @file
+# kBuild configuration for kStuff
+#
+
+#
+# Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kStuff 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+#
+# This is where we install during the build.
+#
+PATH_INS := $(PATH_OUT)/kStuff
+
+
+#
+# Templates for the kStuff.
+#
+TEMPLATE_kStuff = kStuff Template
+TEMPLATE_kStuff_TOOL             = GCC3
+TEMPLATE_kStuff_TOOL.darwin      = GCC4MACHO
+TEMPLATE_kStuff_TOOL.os2         = GCC3OMF
+TEMPLATE_kStuff_TOOL.solaris     = GCC3PLAIN
+TEMPLATE_kStuff_TOOL.win.x86     = VCC70
+TEMPLATE_kStuff_TOOL.win.amd64   = VCC80AMD64
+
+TEMPLATE_kStuff_SDKS.win.x86     = WINPSDK W2K3DDKX86
+TEMPLATE_kStuff_SDKS.win.amd64   = WINPSDK W2K3DDKAMD64
+
+TEMPLATE_kStuff_DEFS.freebsd     = KS_OS_FREEBSD
+TEMPLATE_kStuff_DEFS.darwin      = KS_OS_DARWIN
+TEMPLATE_kStuff_DEFS.linux       = KS_OS_LINUX
+TEMPLATE_kStuff_DEFS.netbsd      = KS_OS_NETBSD
+TEMPLATE_kStuff_DEFS.openbsd     = KS_OS_OPENBSD
+TEMPLATE_kStuff_DEFS.os2         = KS_OS_OS2
+TEMPLATE_kStuff_DEFS.solaris     = KS_OS_SOLARIS
+TEMPLATE_kStuff_DEFS.win         = KS_OS_WINDOWS _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS
+
+TEMPLATE_kStuff_DEFS.x86         = KS_BITS=32
+TEMPLATE_kStuff_DEFS.amd64       = KS_BITS=64
+
+TEMPLATE_kStuff_INCS             = $(PATH_ROOT)/kStuff/include
+
+TEMPLATE_kStuff_ASTOOL           = YASM
+TEMPLATE_kStuff_ASTOOL.os2       = NASM
+TEMPLATE_kStuff_ASFLAGS.freebsd  = -f elf
+TEMPLATE_kStuff_ASFLAGS.linux    = -f elf
+TEMPLATE_kStuff_ASFLAGS.os2      = -f omf
+TEMPLATE_kStuff_ASFLAGS.win.x86  = -f win32 -g cv8
+TEMPLATE_kStuff_ASFLAGS.win.amd64= -f win64 -g cv8
+
+TEMPLATE_kStuff_CFLAGS.darwin    = -g -fno-common
+TEMPLATE_kStuff_CFLAGS.freebsd   = -g
+TEMPLATE_kStuff_CFLAGS.linux     = -g
+TEMPLATE_kStuff_CFLAGS.os2       = -g
+TEMPLATE_kStuff_CFLAGS.win       = -Zi -Zl -MD -W3 -GF -GR-
+ifneq ($(BUILD_TYPE),debug)
+TEMPLATE_kStuff_CFLAGS.freebsd  += -O3
+TEMPLATE_kStuff_CFLAGS.linux    += -O3
+TEMPLATE_kStuff_CFLAGS.os2      += -O3
+TEMPLATE_kStuff_CFLAGS.win      += -O2xtg -Oi -Ob2
+else
+TEMPLATE_kStuff_CFLAGS.win      += -Od
+endif
+
+TEMPLATE_kStuff_CXXFLAGS.darwin  = -g -fno-common
+TEMPLATE_kStuff_CXXFLAGS.freebsd = -g
+TEMPLATE_kStuff_CXXFLAGS.linux   = -g
+TEMPLATE_kStuff_CXXFLAGS.os2     = -g
+TEMPLATE_kStuff_CXXFLAGS.win     = -Zi -Zl -MD -W3 -GF -GR-
+ifneq ($(BUILD_TYPE),debug)
+TEMPLATE_kStuff_CXXFLAGS.freebsd+= -O3
+TEMPLATE_kStuff_CXXFLAGS.linux  += -O3
+TEMPLATE_kStuff_CXXFLAGS.os2    += -O3
+TEMPLATE_kStuff_CXXFLAGS.win    += -O2xtg -Oi -Ob2
+else
+TEMPLATE_kStuff_CXXFLAGS.win    += -Od
+endif
+
+TEMPLATE_kStuff_LDFLAGS.freebsd  = -g
+TEMPLATE_kStuff_LDFLAGS.linux    = -g
+TEMPLATE_kStuff_LDFLAGS.os2      = -g
+TEMPLATE_kStuff_LDFLAGS.win      = /DEBUG /NODEFAULTLIB
+
+TEMPLATE_kStuff_LIBS.freebsd     =
+TEMPLATE_kStuff_LIBS.linux       =
+TEMPLATE_kStuff_LIBS.os2         =
+TEMPLATE_kStuff_LIBS.win         = \
+	$(PATH_SDK_WINPSDK_LIB)/psapi.Lib
+TEMPLATE_kStuff_LIBS.win.x86     = \
+	$(PATH_TOOL_VCC70_LIB)/msvcrt.lib \
+	$(PATH_TOOL_VCC70_LIB)/msvcprt.lib \
+	$(PATH_TOOL_VCC70_LIB)/oldnames.lib \
+	$(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib
+TEMPLATE_kStuff_LIBS.win.amd64   = \
+	$(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib \
+	$(PATH_TOOL_VCC80AMD64_LIB)/msvcprt.lib \
+	$(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \
+	$(PATH_SDK_W2K3DDKAMD64_LIB)/ntdll.lib
+
+TEMPLATE_kStuffEXE = kStuff Executable Template
+TEMPLATE_kStuffEXE_EXTENDS = kStuff
+TEMPLATE_kStuffEXE_DEFS = $(TEMPLATE_kStuff) KS_EXE_TARGET
+
+TEMPLATE_kStuffLIB = kStuff Library Template
+TEMPLATE_kStuffLIB_EXTENDS = kStuff
+TEMPLATE_kStuffLIB_DEFS = $(TEMPLATE_kStuff) KS_LIB_TARGET
+
+TEMPLATE_kStuffDLL = kStuff DLL Template
+TEMPLATE_kStuffDLL_EXTENDS = kStuff
+TEMPLATE_kStuffDLL_DEFS = $(TEMPLATE_kStuff) KS_DLL_TARGET
+TEMPLATE_kStuffDLL_LDFLAGS.os2 = $(TEMPLATE_kStuff_LDFLAGS.os2) -Zdll
+
+
Index: /trunk/Makefile.kmk
===================================================================
--- /trunk/Makefile.kmk	(revision 2)
+++ /trunk/Makefile.kmk	(revision 2)
@@ -0,0 +1,48 @@
+# $Id$
+## @file
+# kStuff - Top-level makefile.
+#
+
+#
+# Copyright (c) 2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kStuff 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+DEPTH ?= ..
+include $(PATH_KBUILD)/subheader.kmk
+
+include $(PATH_SUB_CURRENT)/kCpu/Makefile.kmk
+include $(PATH_SUB_CURRENT)/kDbg/Makefile.kmk
+include $(PATH_SUB_CURRENT)/kErr/Makefile.kmk
+include $(PATH_SUB_CURRENT)/kLdr/Makefile.kmk
+include $(PATH_SUB_CURRENT)/kRdr/Makefile.kmk
+
+include $(PATH_SUB_CURRENT)/kHlp/Makefile.kmk
+include $(PATH_SUB_CURRENT)/kProfiler2/Makefile.kmk
+
+LIBRARIES += kStuffStatic
+kStuffStatic_TEMPLATE = kStuffLIB
+kStuffStatic_SOURCES = \
+	$(TARGET_kCpuStatic) \
+	$(TARGET_kDbgStatic) \
+	$(TARGET_kErrStatic) \
+	$(TARGET_kLdrStatic) \
+	$(TARGET_kRdrStatic)
+
+include $(PATH_KBUILD)/subfooter.kmk
+
Index: /trunk/include/k/kAvlTmpl/kAvlBase.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlBase.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlBase.h	(revision 2)
@@ -0,0 +1,515 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, The Mandatory Base Code.
+ */
+
+/*
+ * Copyright (c) 2001-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+/** @page pg_kAvlTmpl   Template Configuration.
+ *
+ *  This is a templated implementation of AVL trees in C. The template
+ *  parameters relates to the kind of key used and how duplicates are
+ *  treated.
+ *
+ *  \#define KAVL_EQUAL_ALLOWED
+ *  Define this to tell us that equal keys are allowed.
+ *  Then Equal keys will be put in a list pointed to by KAVLNODE::pList.
+ *  This is by default not defined.
+ *
+ *  \#define KAVL_CHECK_FOR_EQUAL_INSERT
+ *  Define this to enable insert check for equal nodes.
+ *  This is by default not defined.
+ *
+ *  \#define KAVL_MAX_STACK
+ *  Use this to specify the max number of stack entries the stack will use when inserting
+ *  and removing nodes from the tree. The size should be something like
+ *      log2(<max nodes>) + 3
+ *  Must be defined.
+ *
+ *  \#define KAVL_RANGE
+ *  Define this to enable key ranges.
+ *
+ *  \#define KAVL_OFFSET
+ *  Define this to link the tree together using self relative offset
+ *  instead of memory pointers, thus making the entire tree relocatable
+ *  provided all the nodes - including the root node variable - are moved
+ *  the exact same distance.
+ *
+ *  \#define KAVLKEY
+ *  Define this to the name of the AVL key type.
+ *
+ *  \#define KAVL_STD_KEY_COMP
+ *  Define this to use the standard key compare macros. If not set all the
+ *  compare operations for KAVLKEY have to be defined: KAVL_G, KAVL_E, KAVL_NE,
+ *  KAVL_R_IS_IDENTICAL, KAVL_R_IS_INTERSECTING and KAVL_R_IS_IN_RANGE. The latter
+ *  three are only required when KAVL_RANGE is defined.
+ *
+ *  \#define KAVLNODE
+ *  Define this to the name (typedef) of the AVL node structure. This
+ *  structure must have a mpLeft, mpRight, mKey and mHeight member.
+ *  If KAVL_RANGE is defined a mKeyLast is also required.
+ *  If KAVL_EQUAL_ALLOWED is defined a mpList member is required.
+ *  It's possible to use other member names by redefining the names.
+ *
+ *  \#define KAVLTREEPTR
+ *  Define this to the name (typedef) of the tree pointer type. This is
+ *  required when KAVL_OFFSET is defined. When not defined it defaults
+ *  to KAVLNODE *.
+ *
+ *  \#define KAVL_FN
+ *  Use this to alter the names of the AVL functions.
+ *  Must be defined.
+ *
+ *  \#define KAVL_TYPE(prefix, name)
+ *  Use this to make external type names and unique. The prefix may be empty.
+ *  Must be defined.
+ *
+ *  \#define KAVL_INT(name)
+ *  Use this to make internal type names and unique. The prefix may be empty.
+ *  Must be defined.
+ *
+ *  \#define KAVL_DECL(rettype)
+ *  Function declaration macro that should be set according to the scope
+ *  the instantiated template should have. For instance an inlined scope
+ *  (private or public) should K_DECL_INLINE(rettype) here.
+ *
+ *  This version of the kAVL tree offers the option of inlining the entire
+ *  implementation. This depends on the compiler doing a decent job in both
+ *  making use of the inlined code and to eliminate const variables.
+ */
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kHlpAssert.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define KAVL_HEIGHTOF(pNode) ((KU8)((pNode) != NULL ? (pNode)->mHeight : 0))
+
+/** @def KAVL_GET_POINTER
+ * Reads a 'pointer' value.
+ *
+ * @returns The native pointer.
+ * @param   pp      Pointer to the pointer to read.
+ * @internal
+ */
+
+/** @def KAVL_GET_POINTER_NULL
+ * Reads a 'pointer' value which can be KAVL_NULL.
+ *
+ * @returns The native pointer.
+ * @returns NULL pointer if KAVL_NULL.
+ * @param   pp      Pointer to the pointer to read.
+ * @internal
+ */
+
+/** @def KAVL_SET_POINTER
+ * Writes a 'pointer' value.
+ * For offset-based schemes offset relative to pp is calculated and assigned to *pp.
+ *
+ * @returns stored pointer.
+ * @param   pp      Pointer to where to store the pointer.
+ * @param   p       Native pointer to assign to *pp.
+ * @internal
+ */
+
+/** @def KAVL_SET_POINTER_NULL
+ * Writes a 'pointer' value which can be KAVL_NULL.
+ *
+ * For offset-based schemes offset relative to pp is calculated and assigned to *pp,
+ * if p is not KAVL_NULL of course.
+ *
+ * @returns stored pointer.
+ * @param   pp      Pointer to where to store the pointer.
+ * @param   pp2     Pointer to where to pointer to assign to pp. This can be KAVL_NULL
+ * @internal
+ */
+
+#ifndef KAVLTREEPTR
+# define KAVLTREEPTR                        KAVLNODE *
+#endif
+
+#ifdef KAVL_OFFSET
+# define KAVL_GET_POINTER(pp)               ( (KAVLNODE *)((KIPTR)(pp) + *(pp)) )
+# define KAVL_GET_POINTER_NULL(pp)          ( *(pp) != KAVL_NULL ? KAVL_GET_POINTER(pp) : NULL )
+# define KAVL_SET_POINTER(pp, p)            ( (*(pp)) = ((KIPTR)(p) - (KIPTR)(pp)) )
+# define KAVL_SET_POINTER_NULL(pp, pp2)     ( (*(pp)) = *(pp2) != KAVL_NULL ? (KIPTR)KAVL_GET_POINTER(pp2) - (KIPTR)(pp) : KAVL_NULL )
+#else
+# define KAVL_GET_POINTER(pp)               ( *(pp) )
+# define KAVL_GET_POINTER_NULL(pp)          ( *(pp) )
+# define KAVL_SET_POINTER(pp, p)            ( (*(pp)) = (p) )
+# define KAVL_SET_POINTER_NULL(pp, pp2)     ( (*(pp)) = *(pp2) )
+#endif
+
+
+/** @def KAVL_NULL
+ * The NULL 'pointer' equivalent.
+ */
+#ifdef KAVL_OFFSET
+# define KAVL_NULL     0
+#else
+# define KAVL_NULL     NULL
+#endif
+
+#ifdef KAVL_STD_KEY_COMP
+# define KAVL_G(key1, key2)                 ( (key1) >  (key2) )
+# define KAVL_E(key1, key2)                 ( (key1) == (key2) )
+# define KAVL_NE(key1, key2)                ( (key1) != (key2) )
+# ifdef KAVL_RANGE
+#  define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E)       ( (key1B) == (key2B) && (key1E) == (key2E) )
+#  define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E)    ( (key1B) <= (key2E) && (key1E) >= (key2B) )
+#  define KAVL_R_IS_IN_RANGE(key1B, key1E, key2)                KAVL_R_IS_INTERSECTING(key1B, key2, key1E, key2)
+# endif
+#endif
+
+#ifndef KAVL_RANGE
+# define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E)     KAVL_E(key1B, key2B)
+# define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E)        KAVL_E(key1B, key2B)
+#endif
+
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Stack used to avoid recursive calls during insert and removal.
+ */
+typedef struct
+{
+    unsigned        cEntries;
+    KAVLTREEPTR    *aEntries[KAVL_MAX_STACK];
+} KAVL_INT(STACK);
+
+/**
+ * The callback used by the Destroy and DoWithAll functions.
+ */
+typedef int (* KAVL_TYPE(PFN,CALLBACK))(KAVLNODE *, void *);
+
+
+
+/**
+ * Rewinds a stack of node pointer pointers, rebalancing the tree.
+ *
+ * @param     pStack  Pointer to stack to rewind.
+ * @sketch    LOOP thru all stack entries
+ *            BEGIN
+ *                Get pointer to pointer to node (and pointer to node) from the stack.
+ *                IF 2 higher left subtree than in right subtree THEN
+ *                BEGIN
+ *                    IF higher (or equal) left-sub-subtree than right-sub-subtree THEN
+ *                                *                       n+2|n+3
+ *                              /   \                     /     \
+ *                            n+2    n       ==>         n+1   n+1|n+2
+ *                           /   \                             /     \
+ *                         n+1 n|n+1                          n|n+1  n
+ *
+ *                         Or with keys:
+ *
+ *                               4                           2
+ *                             /   \                       /   \
+ *                            2     5        ==>          1     4
+ *                           / \                               / \
+ *                          1   3                             3   5
+ *
+ *                    ELSE
+ *                                *                         n+2
+ *                              /   \                      /   \
+ *                            n+2    n                   n+1   n+1
+ *                           /   \           ==>        /  \   /  \
+ *                          n    n+1                    n  L   R   n
+ *                               / \
+ *                              L   R
+ *
+ *                         Or with keys:
+ *                               6                           4
+ *                             /   \                       /   \
+ *                            2     7        ==>          2     6
+ *                          /   \                       /  \  /  \
+ *                          1    4                      1  3  5  7
+ *                              / \
+ *                             3   5
+ *                END
+ *                ELSE IF 2 higher in right subtree than in left subtree THEN
+ *                BEGIN
+ *                    Same as above but left <==> right. (invert the picture)
+ *                ELSE
+ *                    IF correct height THEN break
+ *                    ELSE correct height.
+ *            END
+ */
+K_DECL_INLINE(void) KAVL_FN(Rebalance)(KAVL_INT(STACK) *pStack)
+{
+    while (pStack->cEntries > 0)
+    {
+        KAVLTREEPTR     *ppNode = pStack->aEntries[--pStack->cEntries];
+        KAVLNODE        *pNode = KAVL_GET_POINTER(ppNode);
+        KAVLNODE        *pLeftNode = KAVL_GET_POINTER_NULL(&pNode->mpLeft);
+        KU8              uLeftHeight = KAVL_HEIGHTOF(pLeftNode);
+        KAVLNODE        *pRightNode = KAVL_GET_POINTER_NULL(&pNode->mpRight);
+        KU8              uRightHeight = KAVL_HEIGHTOF(pRightNode);
+
+        if (uRightHeight + 1 < uLeftHeight)
+        {
+            KAVLNODE    *pLeftLeftNode = KAVL_GET_POINTER_NULL(&pLeftNode->mpLeft);
+            KAVLNODE    *pLeftRightNode = KAVL_GET_POINTER_NULL(&pLeftNode->mpRight);
+            KU8          uLeftRightHeight = KAVL_HEIGHTOF(pLeftRightNode);
+
+            if (KAVL_HEIGHTOF(pLeftLeftNode) >= uLeftRightHeight)
+            {
+                KAVL_SET_POINTER_NULL(&pNode->mpLeft, &pLeftNode->mpRight);
+                KAVL_SET_POINTER(&pLeftNode->mpRight, pNode);
+                pLeftNode->mHeight = (KU8)(1 + (pNode->mHeight = (KU8)(1 + uLeftRightHeight)));
+                KAVL_SET_POINTER(ppNode, pLeftNode);
+            }
+            else
+            {
+                KAVL_SET_POINTER_NULL(&pLeftNode->mpRight, &pLeftRightNode->mpLeft);
+                KAVL_SET_POINTER_NULL(&pNode->mpLeft, &pLeftRightNode->mpRight);
+                KAVL_SET_POINTER(&pLeftRightNode->mpLeft, pLeftNode);
+                KAVL_SET_POINTER(&pLeftRightNode->mpRight, pNode);
+                pLeftNode->mHeight = pNode->mHeight = uLeftRightHeight;
+                pLeftRightNode->mHeight = uLeftHeight;
+                KAVL_SET_POINTER(ppNode, pLeftRightNode);
+            }
+        }
+        else if (uLeftHeight + 1 < uRightHeight)
+        {
+            KAVLNODE    *pRightLeftNode = KAVL_GET_POINTER_NULL(&pRightNode->mpLeft);
+            KU8          uRightLeftHeight = KAVL_HEIGHTOF(pRightLeftNode);
+            KAVLNODE    *pRightRightNode = KAVL_GET_POINTER_NULL(&pRightNode->mpRight);
+
+            if (KAVL_HEIGHTOF(pRightRightNode) >= uRightLeftHeight)
+            {
+                KAVL_SET_POINTER_NULL(&pNode->mpRight, &pRightNode->mpLeft);
+                KAVL_SET_POINTER(&pRightNode->mpLeft, pNode);
+                pRightNode->mHeight = (KU8)(1 + (pNode->mHeight = (KU8)(1 + uRightLeftHeight)));
+                KAVL_SET_POINTER(ppNode, pRightNode);
+            }
+            else
+            {
+                KAVL_SET_POINTER_NULL(&pRightNode->mpLeft, &pRightLeftNode->mpRight);
+                KAVL_SET_POINTER_NULL(&pNode->mpRight, &pRightLeftNode->mpLeft);
+                KAVL_SET_POINTER(&pRightLeftNode->mpRight, pRightNode);
+                KAVL_SET_POINTER(&pRightLeftNode->mpLeft, pNode);
+                pRightNode->mHeight = pNode->mHeight = uRightLeftHeight;
+                pRightLeftNode->mHeight = uRightHeight;
+                KAVL_SET_POINTER(ppNode, pRightLeftNode);
+            }
+        }
+        else
+        {
+            KU8 uHeight = (KU8)(K_MAX(uLeftHeight, uRightHeight) + 1);
+            if (uHeight == pNode->mHeight)
+                break;
+            pNode->mHeight = uHeight;
+        }
+    }
+
+}
+
+
+/**
+ * Inserts a node into the AVL-tree.
+ * @returns   TRUE if inserted.
+ *            FALSE if node exists in tree.
+ * @param     ppTree  Pointer to the AVL-tree root node pointer.
+ * @param     pNode   Pointer to the node which is to be added.
+ * @sketch    Find the location of the node (using binary tree algorithm.):
+ *            LOOP until NULL leaf pointer
+ *            BEGIN
+ *                Add node pointer pointer to the AVL-stack.
+ *                IF new-node-key < node key THEN
+ *                    left
+ *                ELSE
+ *                    right
+ *            END
+ *            Fill in leaf node and insert it.
+ *            Rebalance the tree.
+ */
+KAVL_DECL(KBOOL) KAVL_FN(Insert)(KAVLTREEPTR *ppTree, KAVLNODE *pNode)
+{
+    KAVL_INT(STACK)     AVLStack;
+    KAVLTREEPTR        *ppCurNode = ppTree;
+    register KAVLKEY    Key = pNode->mKey;
+#ifdef KAVL_RANGE
+    register KAVLKEY    KeyLast = pNode->mKeyLast;
+#endif
+
+#ifdef KAVL_RANGE
+    if (Key > KeyLast)
+        return false;
+#endif
+
+    AVLStack.cEntries = 0;
+    while (*ppCurNode != KAVL_NULL)
+    {
+        register KAVLNODE *pCurNode = KAVL_GET_POINTER(ppCurNode);
+
+        kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK);
+        AVLStack.aEntries[AVLStack.cEntries++] = ppCurNode;
+#ifdef KAVL_EQUAL_ALLOWED
+        if (KAVL_R_IS_IDENTICAL(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast))
+        {
+            /*
+             * If equal then we'll use a list of equal nodes.
+             */
+            pNode->mpLeft = pNode->mpRight = KAVL_NULL;
+            pNode->mHeight = 0;
+            KAVL_SET_POINTER_NULL(&pNode->mpList, &pCurNode->mpList);
+            KAVL_SET_POINTER(&pCurNode->mpList, pNode);
+            return K_TRUE;
+        }
+#endif
+#ifdef KAVL_CHECK_FOR_EQUAL_INSERT
+        if (KAVL_R_IS_INTERSECTING(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast))
+            return K_FALSE;
+#endif
+        if (KAVL_G(pCurNode->mKey, Key))
+            ppCurNode = &pCurNode->mpLeft;
+        else
+            ppCurNode = &pCurNode->mpRight;
+    }
+
+    pNode->mpLeft = pNode->mpRight = KAVL_NULL;
+#ifdef KAVL_EQUAL_ALLOWED
+    pNode->mpList = KAVL_NULL;
+#endif
+    pNode->mHeight = 1;
+    KAVL_SET_POINTER(ppCurNode, pNode);
+
+    KAVL_FN(Rebalance)(&AVLStack);
+    return K_TRUE;
+}
+
+
+/**
+ * Removes a node from the AVL-tree.
+ * @returns   Pointer to the node.
+ * @param     ppTree  Pointer to the AVL-tree root node pointer.
+ * @param     Key     Key value of the node which is to be removed.
+ * @sketch    Find the node which is to be removed:
+ *            LOOP until not found
+ *            BEGIN
+ *                Add node pointer pointer to the AVL-stack.
+ *                IF the keys matches THEN break!
+ *                IF remove key < node key THEN
+ *                    left
+ *                ELSE
+ *                    right
+ *            END
+ *            IF found THEN
+ *            BEGIN
+ *                IF left node not empty THEN
+ *                BEGIN
+ *                    Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack:
+ *                    Start at left node.
+ *                    LOOP until right node is empty
+ *                    BEGIN
+ *                        Add to stack.
+ *                        go right.
+ *                    END
+ *                    Link out the found node.
+ *                    Replace the node which is to be removed with the found node.
+ *                    Correct the stack entry for the pointer to the left tree.
+ *                END
+ *                ELSE
+ *                BEGIN
+ *                    Move up right node.
+ *                    Remove last stack entry.
+ *                END
+ *                Balance tree using stack.
+ *            END
+ *            return pointer to the removed node (if found).
+ */
+KAVL_DECL(KAVLNODE *) KAVL_FN(Remove)(KAVLTREEPTR *ppTree, KAVLKEY Key)
+{
+    KAVL_INT(STACK)     AVLStack;
+    KAVLTREEPTR        *ppDeleteNode = ppTree;
+    register KAVLNODE  *pDeleteNode;
+
+    AVLStack.cEntries = 0;
+    for (;;)
+    {
+        if (*ppDeleteNode == KAVL_NULL)
+            return NULL;
+        pDeleteNode = KAVL_GET_POINTER(ppDeleteNode);
+
+        kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK);
+        AVLStack.aEntries[AVLStack.cEntries++] = ppDeleteNode;
+        if (KAVL_E(pDeleteNode->mKey, Key))
+            break;
+
+        if (KAVL_G(pDeleteNode->mKey, Key))
+            ppDeleteNode = &pDeleteNode->mpLeft;
+        else
+            ppDeleteNode = &pDeleteNode->mpRight;
+    }
+
+    if (pDeleteNode->mpLeft != KAVL_NULL)
+    {
+        /* find the rightmost node in the left tree. */
+        const unsigned      iStackEntry = AVLStack.cEntries;
+        KAVLTREEPTR        *ppLeftLeast = &pDeleteNode->mpLeft;
+        register KAVLNODE  *pLeftLeast = KAVL_GET_POINTER(ppLeftLeast);
+
+        while (pLeftLeast->mpRight != KAVL_NULL)
+        {
+            kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK);
+            AVLStack.aEntries[AVLStack.cEntries++] = ppLeftLeast;
+            ppLeftLeast = &pLeftLeast->mpRight;
+            pLeftLeast  = KAVL_GET_POINTER(ppLeftLeast);
+        }
+
+        /* link out pLeftLeast */
+        KAVL_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->mpLeft);
+
+        /* link it in place of the delete node. */
+        KAVL_SET_POINTER_NULL(&pLeftLeast->mpLeft, &pDeleteNode->mpLeft);
+        KAVL_SET_POINTER_NULL(&pLeftLeast->mpRight, &pDeleteNode->mpRight);
+        pLeftLeast->mHeight = pDeleteNode->mHeight;
+        KAVL_SET_POINTER(ppDeleteNode, pLeftLeast);
+        AVLStack.aEntries[iStackEntry] = &pLeftLeast->mpLeft;
+    }
+    else
+    {
+        KAVL_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->mpRight);
+        AVLStack.cEntries--;
+    }
+
+    KAVL_FN(Rebalance)(&AVLStack);
+    return pDeleteNode;
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlDestroy.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlDestroy.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlDestroy.h	(revision 2)
@@ -0,0 +1,111 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, Destroy the tree.
+ */
+
+/*
+ * Copyright (c) 1999-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+
+/**
+ * Destroys the specified tree, starting with the root node and working our way down.
+ *
+ * @returns 0 on success.
+ * @returns Return value from callback on failure. On failure, the tree will be in
+ *          an unbalanced condition and only further calls to the Destroy should be
+ *          made on it. Note that the node we fail on will be considered dead and
+ *          no action is taken to link it back into the tree.
+ * @param   ppTree          Pointer to the AVL-tree root node pointer.
+ * @param   pfnCallBack     Pointer to callback function.
+ * @param   pvUser          User parameter passed on to the callback function.
+ */
+KAVL_DECL(int) KAVL_FN(Destroy)(KAVLTREEPTR *ppTree, KAVL_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser)
+{
+    unsigned    cEntries;
+    KAVLNODE   *apEntries[KAVL_MAX_STACK];
+    int         rc;
+
+    if (*ppTree == KAVL_NULL)
+        return 0;
+
+    cEntries = 1;
+    apEntries[0] = KAVL_GET_POINTER(ppTree);
+    while (cEntries > 0)
+    {
+        /*
+         * Process the subtrees first.
+         */
+        KAVLNODE *pNode = apEntries[cEntries - 1];
+        if (pNode->mpLeft != KAVL_NULL)
+            apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft);
+        else if (pNode->mpRight != KAVL_NULL)
+            apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->mpRight);
+        else
+        {
+#ifdef KAVL_EQUAL_ALLOWED
+            /*
+             * Process nodes with the same key.
+             */
+            while (pNode->pList != KAVL_NULL)
+            {
+                KAVLNODE *pEqual = KAVL_GET_POINTER(&pNode->pList);
+                KAVL_SET_POINTER(&pNode->pList, KAVL_GET_POINTER_NULL(&pEqual->pList));
+                pEqual->pList = KAVL_NULL;
+
+                rc = pfnCallBack(pEqual, pvUser);
+                if (rc)
+                    return rc;
+            }
+#endif
+
+            /*
+             * Unlink the node.
+             */
+            if (--cEntries > 0)
+            {
+                KAVLNODE *pParent = apEntries[cEntries - 1];
+                if (KAVL_GET_POINTER(&pParent->mpLeft) == pNode)
+                    pParent->mpLeft = KAVL_NULL;
+                else
+                    pParent->mpRight = KAVL_NULL;
+            }
+            else
+                *ppTree = KAVL_NULL;
+
+            kHlpAssert(pNode->mpLeft == KAVL_NULL);
+            kHlpAssert(pNode->mpRight == KAVL_NULL);
+            rc = pfnCallBack(pNode, pvUser);
+            if (rc)
+                return rc;
+        }
+    } /* while */
+    kHlpAssert(*ppTree == KAVL_NULL);
+
+    return 0;
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlDoWithAll.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlDoWithAll.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlDoWithAll.h	(revision 2)
@@ -0,0 +1,157 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, The Callback Iterator.
+ */
+
+/*
+ * Copyright (c) 1999-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Stack used by DoWithAll to avoid recusive function calls.
+ */
+typedef struct
+{
+    unsigned        cEntries;
+    KAVLNODE       *aEntries[KAVL_MAX_STACK];
+    char            achFlags[KAVL_MAX_STACK];
+} KAVL_INT(STACK2);
+
+
+/**
+ * Iterates thru all nodes in the given tree.
+ *
+ * @returns   0 on success. Return from callback on failure.
+ * @param     ppTree       Pointer to the AVL-tree root node pointer.
+ * @param     fFromLeft    K_TRUE:  Left to right.
+ *                         K_FALSE: Right to left.
+ * @param     pfnCallBack  Pointer to callback function.
+ * @param     pvUser       User parameter passed on to the callback function.
+ */
+KAVL_DECL(int) KAVL_FN(DoWithAll)(KAVLTREEPTR *ppTree, KBOOL fFromLeft, KAVL_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser)
+{
+    KAVL_INT(STACK2)    AVLStack;
+    KAVLNODE           *pNode;
+#ifdef KAVL_EQUAL_ALLOWED
+    KAVLNODE           *pEqual;
+#endif
+    int                 rc;
+
+    if (*ppTree == KAVL_NULL)
+        return 0;
+
+    AVLStack.cEntries = 1;
+    AVLStack.achFlags[0] = 0;
+    AVLStack.aEntries[0] = KAVL_GET_POINTER(ppTree);
+
+    if (fFromLeft)
+    {   /* from left */
+        while (AVLStack.cEntries > 0)
+        {
+            pNode = AVLStack.aEntries[AVLStack.cEntries - 1];
+
+            /* left */
+            if (!AVLStack.achFlags[AVLStack.cEntries - 1]++)
+            {
+                if (pNode->mpLeft != KAVL_NULL)
+                {
+                    AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */
+                    AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft);
+                    continue;
+                }
+            }
+
+            /* center */
+            rc = pfnCallBack(pNode, pvUser);
+            if (rc)
+                return rc;
+#ifdef KAVL_EQUAL_ALLOWED
+            if (pNode->mpList != KAVL_NULL)
+                for (pEqual = KAVL_GET_POINTER(&pNode->mpList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->mpList))
+                {
+                    rc = pfnCallBack(pEqual, pvUser);
+                    if (rc)
+                        return rc;
+                }
+#endif
+
+            /* right */
+            AVLStack.cEntries--;
+            if (pNode->mpRight != KAVL_NULL)
+            {
+                AVLStack.achFlags[AVLStack.cEntries] = 0;
+                AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpRight);
+            }
+        } /* while */
+    }
+    else
+    {   /* from right */
+        while (AVLStack.cEntries > 0)
+        {
+            pNode = AVLStack.aEntries[AVLStack.cEntries - 1];
+
+            /* right */
+            if (!AVLStack.achFlags[AVLStack.cEntries - 1]++)
+            {
+                if (pNode->mpRight != KAVL_NULL)
+                {
+                    AVLStack.achFlags[AVLStack.cEntries] = 0;  /* 0 first, 1 last */
+                    AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpRight);
+                    continue;
+                }
+            }
+
+            /* center */
+            rc = pfnCallBack(pNode, pvUser);
+            if (rc)
+                return rc;
+#ifdef KAVL_EQUAL_ALLOWED
+            if (pNode->mpList != KAVL_NULL)
+                for (pEqual = KAVL_GET_POINTER(&pNode->mpList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->pList))
+                {
+                    rc = pfnCallBack(pEqual, pvUser);
+                    if (rc)
+                        return rc;
+                }
+#endif
+
+            /* left */
+            AVLStack.cEntries--;
+            if (pNode->mpLeft != KAVL_NULL)
+            {
+                AVLStack.achFlags[AVLStack.cEntries] = 0;
+                AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft);
+            }
+        } /* while */
+    }
+
+    return 0;
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlEnum.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlEnum.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlEnum.h	(revision 2)
@@ -0,0 +1,162 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, Node Enumeration.
+ */
+
+/*
+ * Copyright (c) 1999-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Enumeration control data.
+ *
+ * This is initialized by BeginEnum and used by GetNext to figure out what
+ * to do next.
+ */
+typedef struct KAVL_TYPE(,ENUMDATA)
+{
+    KBOOL               fFromLeft;
+    KI8                 cEntries;
+    KU8                 achFlags[KAVL_MAX_STACK];
+    KAVLNODE *          aEntries[KAVL_MAX_STACK];
+} KAVL_TYPE(,ENUMDATA), *KAVL_TYPE(P,ENUMDATA);
+
+
+/**
+ * Get the next node in the tree enumeration.
+ *
+ * The current implementation of this function willl not walk the mpList
+ * chain like the DoWithAll function does. This may be changed later.
+ *
+ * @returns Pointer to the first node in the tree.
+ * @param   pEnumData   Pointer to enumeration control data.
+ */
+KAVL_DECL(KAVLNODE *) KAVL_FN(GetNext)(KAVL_TYPE(,ENUMDATA) *pEnumData)
+{
+    if (pEnumData->fFromLeft)
+    {   /* from left */
+        while (pEnumData->cEntries > 0)
+        {
+            KAVLNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1];
+
+            /* left */
+            if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0)
+            {
+                pEnumData->achFlags[pEnumData->cEntries - 1]++;
+                if (pNode->mpLeft != KAVL_NULL)
+                {
+                    pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 left, 1 center, 2 right */
+                    pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft);
+                    continue;
+                }
+            }
+
+            /* center */
+            if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1)
+            {
+                pEnumData->achFlags[pEnumData->cEntries - 1]++;
+                return pNode;
+            }
+
+            /* right */
+            pEnumData->cEntries--;
+            if (pNode->mpRight != KAVL_NULL)
+            {
+                pEnumData->achFlags[pEnumData->cEntries] = 0;
+                pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpRight);
+            }
+        } /* while */
+    }
+    else
+    {   /* from right */
+        while (pEnumData->cEntries > 0)
+        {
+            KAVLNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1];
+
+            /* right */
+            if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0)
+            {
+                pEnumData->achFlags[pEnumData->cEntries - 1]++;
+                if (pNode->mpRight != KAVL_NULL)
+                {
+                    pEnumData->achFlags[pEnumData->cEntries] = 0;  /* 0 right, 1 center, 2 left */
+                    pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpRight);
+                    continue;
+                }
+            }
+
+            /* center */
+            if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1)
+            {
+                pEnumData->achFlags[pEnumData->cEntries - 1]++;
+                return pNode;
+            }
+
+            /* left */
+            pEnumData->cEntries--;
+            if (pNode->mpLeft != KAVL_NULL)
+            {
+                pEnumData->achFlags[pEnumData->cEntries] = 0;
+                pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft);
+            }
+        } /* while */
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Starts an enumeration of all nodes in the given AVL tree.
+ *
+ * The current implementation of this function willl not walk the mpList
+ * chain like the DoWithAll function does. This may be changed later.
+ *
+ * @returns Pointer to the first node in the enumeration.
+ * @param   ppTree      Pointer to the AVL-tree root node pointer.
+ * @param   pEnumData   Pointer to enumeration control data.
+ * @param   fFromLeft   K_TRUE:  Left to right.
+ *                      K_FALSE: Right to left.
+ */
+KAVL_DECL(KAVLNODE *) KAVL_FN(BeginEnum)(KAVLTREEPTR *ppTree, KAVL_TYPE(,ENUMDATA) *pEnumData, KBOOL fFromLeft)
+{
+    if (*ppTree != KAVL_NULL)
+    {
+        pEnumData->fFromLeft = fFromLeft;
+        pEnumData->cEntries = 1;
+        pEnumData->aEntries[0] = KAVL_GET_POINTER(ppTree);
+        pEnumData->achFlags[0] = 0;
+    }
+    else
+        pEnumData->cEntries = 0;
+
+    return KAVL_FN(GetNext)(pEnumData);
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlGet.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlGet.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlGet.h	(revision 2)
@@ -0,0 +1,66 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, Get a Node.
+ */
+
+/*
+ * Copyright (c) 1999-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+
+/**
+ * Gets a node from the tree (does not remove it!)
+ *
+ * @returns   Pointer to the node holding the given key.
+ * @param     ppTree  Pointer to the AVL-tree root node pointer.
+ * @param     Key     Key value of the node which is to be found.
+ */
+KAVL_DECL(KAVLNODE *) KAVL_FN(Get)(KAVLTREEPTR *ppTree, KAVLKEY Key)
+{
+    KAVLNODE *pNode;
+    if (*ppTree == KAVL_NULL)
+        return NULL;
+
+    pNode = KAVL_GET_POINTER(ppTree);
+    while (KAVL_NE(pNode->mKey, Key))
+    {
+        if (KAVL_G(pNode->mKey, Key))
+        {
+            if (pNode->mpLeft == KAVL_NULL)
+                return NULL;
+            pNode = KAVL_GET_POINTER(&pNode->mpLeft);
+        }
+        else
+        {
+            if (pNode->mpRight == KAVL_NULL)
+                return NULL;
+            pNode = KAVL_GET_POINTER(&pNode->mpRight);
+        }
+    }
+    return pNode;
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlGetBestFit.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlGetBestFit.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlGetBestFit.h	(revision 2)
@@ -0,0 +1,99 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, Get Best Fitting Node.
+ */
+
+/*
+ * Copyright (c) 1999-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+
+/**
+ * Finds the best fitting node in the tree for the given Key value.
+ *
+ * @returns Pointer to the best fitting node found.
+ * @param   ppTree      Pointer to Pointer to the tree root node.
+ * @param   Key         The Key of which is to be found a best fitting match for..
+ * @param   fAbove      K_TRUE:  Returned node is have the closest key to Key from above.
+ *                      K_FALSE: Returned node is have the closest key to Key from below.
+ * @sketch  The best fitting node is always located in the searchpath above you.
+ *          >= (above): The node where you last turned left.
+ *          <= (below): the node where you last turned right.
+ */
+KAVL_DECL(KAVLNODE *) KAVL_FN(GetBestFit)(KAVLTREEPTR *ppTree, KAVLKEY Key, KBOOL fAbove)
+{
+    register KAVLNODE  *pNode;
+    KAVLNODE           *pNodeLast;
+
+    if (*ppTree == KAVL_NULL)
+        return NULL;
+
+    pNode = KAVL_GET_POINTER(ppTree);
+    pNodeLast = NULL;
+    if (fAbove)
+    {   /* pNode->mKey >= Key */
+        while (KAVL_NE(pNode->mKey, Key))
+        {
+            if (KAVL_G(pNode->mKey, Key))
+            {
+                if (pNode->mpLeft == KAVL_NULL)
+                    return pNode;
+                pNodeLast = pNode;
+                pNode = KAVL_GET_POINTER(&pNode->mpLeft);
+            }
+            else
+            {
+                if (pNode->mpRight == KAVL_NULL)
+                    return pNodeLast;
+                pNode = KAVL_GET_POINTER(&pNode->mpRight);
+            }
+        }
+    }
+    else
+    {   /* pNode->mKey <= Key */
+        while (KAVL_NE(pNode->mKey, Key))
+        {
+            if (KAVL_G(pNode->mKey, Key))
+            {
+                if (pNode->mpLeft == KAVL_NULL)
+                    return pNodeLast;
+                pNode = KAVL_GET_POINTER(&pNode->mpLeft);
+            }
+            else
+            {
+                if (pNode->mpRight == KAVL_NULL)
+                    return pNode;
+                pNodeLast = pNode;
+                pNode = KAVL_GET_POINTER(&pNode->mpRight);
+            }
+        }
+    }
+
+    /* perfect match or nothing. */
+    return pNode;
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlGetWithParent.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlGetWithParent.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlGetWithParent.h	(revision 2)
@@ -0,0 +1,63 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, Get Node With Parent.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+
+/**
+ * Gets a node from the tree and its parent node (if any).
+ * The tree remains unchanged.
+ *
+ * @returns   Pointer to the node holding the given key.
+ * @param     ppTree    Pointer to the AVL-tree root node pointer.
+ * @param     ppParent  Pointer to a variable which will hold the pointer to the partent node on
+ *                      return. When no node is found, this will hold the last searched node.
+ * @param     Key       Key value of the node which is to be found.
+ */
+KAVL_DECL(KAVLNODE *) KAVL_FN(GetWithParent)(KAVLTREEPTR *ppTree, KAVLNODE **ppParent, KAVLKEY Key)
+{
+    register KAVLNODE *pNode = KAVL_GET_POINTER_NULL(ppTree);
+    register KAVLNODE *pParent = NULL;
+
+    while (     pNode != NULL
+           &&   KAVL_NE(pNode->mKey, Key))
+    {
+        pParent = pNode;
+        if (KAVL_G(pNode->mKey, Key))
+            pNode = KAVL_GET_POINTER_NULL(&pNode->mpLeft);
+        else
+            pNode = KAVL_GET_POINTER_NULL(&pNode->mpRight);
+    }
+
+    *ppParent = pParent;
+    return pNode;
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlRemove2.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlRemove2.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlRemove2.h	(revision 2)
@@ -0,0 +1,126 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, Remove A Specific Node.
+ */
+
+/*
+ * Copyright (c) 1999-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+
+/**
+ * Removes the specified node from the tree.
+ *
+ * @returns Pointer to the removed node (NULL if not in the tree)
+ * @param   ppTree      Pointer to Pointer to the tree root node.
+ * @param   Key         The Key of which is to be found a best fitting match for..
+ *
+ * @remark  This implementation isn't the most efficient, but this short and
+ *          easier to manage.
+ */
+KAVL_DECL(KAVLNODE *) KAVL_FN(Remove2)(KAVLTREEPTR *ppTree, KAVLNODE *pNode)
+{
+#ifdef KAVL_EQUAL_ALLOWED
+    /*
+     * Find the right node by key and see if it's what we want.
+     */
+    KAVLNODE *pParent;
+    KAVLNODE *pCurNode = KAVL_FN(GetWithParent)(ppTree, pNode->mKey, &pParent);
+    if (!pCurNode)
+        return NULL;
+    if (pCurNode != pNode)
+    {
+        /*
+         * It's not the one we want, but it could be in the duplicate list.
+         */
+        while (pCurNode->mpList != KAVL_NULL)
+        {
+            KAVLNODE *pNext = KAVL_GET_POINTER(&pCurNode->mpList);
+            if (pNext == pNode)
+            {
+                KAVL_SET_POINTER_NULL(&pCurNode->mpList, KAVL_GET_POINTER_NULL(&pNode->mpList));
+                pNode->mpList = KAVL_NULL;
+                return pNode;
+            }
+            pCurNode = pNext;
+        }
+        return NULL;
+    }
+
+    /*
+     * Ok, it's the one we want alright.
+     *
+     * Simply remove it if it's the only one with they Key,
+     * if there are duplicates we'll have to unlink it and
+     * insert the first duplicate in our place.
+     */
+    if (pNode->mpList == KAVL_NODE)
+        KAVL_FN(Remove)(ppTree, pNode->mKey);
+    else
+    {
+        KAVLNODE *pNewUs = KAVL_GET_POINTER(&pNode->mpList);
+
+        pNewUs->mHeight = pNode->mHeight;
+
+        if (pNode->mpLeft != KAVL_NULL)
+            KAVL_SET_POINTER(&pNewUs->mpLeft, KAVL_GET_POINTER(&pNode->mpLeft))
+        else
+            pNewUs->mpLeft = KAVL_NULL;
+
+        if (pNode->mpRight != KAVL_NULL)
+            KAVL_SET_POINTER(&pNewUs->mpRight, KAVL_GET_POINTER(&pNode->mpRight))
+        else
+            pNewUs->mpRight = KAVL_NULL;
+
+        if (pParent)
+        {
+            if (KAVL_GET_POINTER_NULL(&pParent->mpLeft) == pNode)
+                KAVL_SET_POINTER(&pParent->mpLeft, pNewUs);
+            else
+                KAVL_SET_POINTER(&pParent->mpRight, pNewUs);
+        }
+        else
+            KAVL_SET_POINTER(ppTree, pNewUs);
+    }
+    return pNode;
+
+#else
+    /*
+     * Delete it, if we got the wrong one, reinsert it.
+     *
+     * This ASSUMS that the caller is NOT going to hand us a lot
+     * of wrong nodes but just uses this API for his convenience.
+     */
+    KAVLNODE *pRemovedNode = KAVL_FN(Remove)(ppTree, pNode->mKey);
+    if (pRemovedNode == pNode)
+        return pRemovedNode;
+
+    KAVL_FN(Insert)(ppTree, pRemovedNode);
+    return NULL;
+#endif
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlRemoveBestFit.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlRemoveBestFit.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlRemoveBestFit.h	(revision 2)
@@ -0,0 +1,70 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Templated AVL Trees, Remove Best Fitting Node.
+ */
+
+/*
+ * Copyright (c) 1999-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+
+/**
+ * Finds the best fitting node in the tree for the given Key value and removes the node.
+ *
+ * @returns Pointer to the removed node.
+ * @param   ppTree      Pointer to Pointer to the tree root node.
+ * @param   Key         The Key of which is to be found a best fitting match for..
+ * @param   fAbove      K_TRUE:  Returned node is have the closest key to Key from above.
+ *                      K_FALSE: Returned node is have the closest key to Key from below.
+ *
+ * @remark  This implementation uses GetBestFit and then Remove and might therefore
+ *          not be the most optimal kind of implementation, but it reduces the complexity
+ *          code size, and the likelyhood for bugs.
+ */
+KAVL_DECL(KAVLNODE *) KAVL_FN(RemoveBestFit)(KAVLTREEPTR *ppTree, KAVLKEY Key, KBOOL fAbove)
+{
+    /*
+     * If we find anything we'll have to remove the node and return it.
+     * Now, if duplicate keys are allowed we'll remove a duplicate before
+     * removing the in-tree node as this is way cheaper.
+     */
+    KAVLNODE *pNode = KAVL_FN(GetBestFit)(ppTree, Key, fAbove);
+    if (pNode != NULL)
+    {
+#ifdef KAVL_EQUAL_ALLOWED
+        if (pNode->mpList != KAVL_NULL)
+        {
+            KAVLNODE *pRet = KAVL_GET_POINTER(&pNode->mpList);
+            KAVL_SET_POINTER_NULL(&pNode->mpList, &pRet->mpList);
+            return pRet;
+        }
+#endif
+        pNode = KAVL_FN(Remove)(ppTree, pNode->mKey);
+    }
+    return pNode;
+}
+
Index: /trunk/include/k/kAvlTmpl/kAvlUndef.h
===================================================================
--- /trunk/include/k/kAvlTmpl/kAvlUndef.h	(revision 2)
+++ /trunk/include/k/kAvlTmpl/kAvlUndef.h	(revision 2)
@@ -0,0 +1,72 @@
+/* $Id$ */
+/** @file
+ * kAvlTmpl - Undefines All Macros (both config and temp).
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ * As a special exception, since this is a source file and not a header
+ * file, you are granted permission to #include this file as you wish
+ * without this in itself causing the resulting program or whatever to be
+ * covered by the LGPL  license. This exception does not however invalidate
+ * any other reasons why the resulting program/whatever should not be
+ * covered the LGPL or GPL.
+ */
+
+/*
+ * The configuration.
+ */
+#undef KAVL_EQUAL_ALLOWED
+#undef KAVL_CHECK_FOR_EQUAL_INSERT
+#undef KAVL_MAX_STACK
+#undef KAVL_RANGE
+#undef KAVL_OFFSET
+#undef KAVL_STD_KEY_COMP
+#undef KAVLKEY
+#undef KAVLNODE
+#undef KAVLTREEPTR
+#undef KAVL_FN
+#undef KAVL_TYPE
+#undef KAVL_INT
+#undef KAVL_DECL
+#undef mKey
+#undef mKeyLast
+#undef mHeight
+#undef mpLeft
+#undef mpRight
+#undef mpList
+
+/*
+ * The internal macros.
+ */
+#undef KAVL_HEIGHTOF
+#undef KAVL_GET_POINTER
+#undef KAVL_GET_POINTER_NULL
+#undef KAVL_SET_POINTER
+#undef KAVL_SET_POINTER_NULL
+#undef KAVL_NULL
+#undef KAVL_G
+#undef KAVL_E
+#undef KAVL_NE
+#undef KAVL_R_IS_IDENTICAL
+#undef KAVL_R_IS_INTERSECTING
+#undef KAVL_R_IS_IN_RANGE
+
Index: /trunk/include/k/kAvlU32.h
===================================================================
--- /trunk/include/k/kAvlU32.h	(revision 2)
+++ /trunk/include/k/kAvlU32.h	(revision 2)
@@ -0,0 +1,62 @@
+/* $Id$ */
+/** @file
+ * kAvl - AVL Tree Implementation, KU32 keys.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___k_kAvlU32_h___
+#define ___k_kAvlU32_h___
+
+typedef struct KAVLU32
+{
+    KU32                mKey;
+    KU8                 mHeight;
+    struct KAVLU32     *mpLeft;
+    struct KAVLU32     *mpRight;
+} KAVLU32, *PKAVLU32, **PPKAVLU32;
+
+/*#define KAVL_EQUAL_ALLOWED*/
+#define KAVL_CHECK_FOR_EQUAL_INSERT
+#define KAVL_MAX_STACK          32
+/*#define KAVL_RANGE */
+/*#define KAVL_OFFSET */
+#define KAVL_STD_KEY_COMP
+#define KAVLKEY                 KU32
+#define KAVLNODE            KAVLU32
+#define KAVL_FN(name)           kAvlU32 ## name
+#define KAVL_TYPE(prefix,name)  prefix ## KAVLU32 ## name
+#define KAVL_INT(name)          KAVLU32INT ## name
+#define KAVL_DECL(rettype)      K_DECL_INLINE(rettype)
+
+#include <k/kAvlTmpl/kAvlBase.h>
+#include <k/kAvlTmpl/kAvlDoWithAll.h>
+#include <k/kAvlTmpl/kAvlEnum.h>
+#include <k/kAvlTmpl/kAvlGet.h>
+#include <k/kAvlTmpl/kAvlGetBestFit.h>
+#include <k/kAvlTmpl/kAvlGetWithParent.h>
+#include <k/kAvlTmpl/kAvlRemove2.h>
+#include <k/kAvlTmpl/kAvlRemoveBestFit.h>
+#include <k/kAvlTmpl/kAvlUndef.h>
+
+#endif
+
Index: /trunk/include/k/kAvloU32.h
===================================================================
--- /trunk/include/k/kAvloU32.h	(revision 2)
+++ /trunk/include/k/kAvloU32.h	(revision 2)
@@ -0,0 +1,71 @@
+/* $Id$ */
+/** @file
+ * kAvl - AVL Tree Implementation, KU32 keys, Offset Based.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___k_kAvloU32_h___
+#define ___k_kAvloU32_h___
+
+typedef KI32 KAVLOU32PTR;
+
+typedef struct KAVLOU32
+{
+    KU32                u32;
+    KU8                 cFloorsToGo;
+    KAVLOU32PTR         offLeft;
+    KAVLOU32PTR         offRight;
+} KAVLOU32, *PKAVLOU32, **PPKAVLOU32;
+
+#define mKey                    u32
+#define mHeight                 cFloorsToGo
+#define mpLeft                  offLeft
+#define mpRight                 offRight
+
+/*#define KAVL_EQUAL_ALLOWED*/
+#define KAVL_CHECK_FOR_EQUAL_INSERT
+#define KAVL_MAX_STACK          32
+/*#define KAVL_RANGE */
+#define KAVL_OFFSET
+#define KAVL_STD_KEY_COMP
+#define KAVLKEY                 KU32
+#define KAVLTREEPTR             KAVLOU32PTR
+#define KAVLNODE                KAVLOU32
+#define KAVL_FN(name)           kAvloU32 ## name
+#define KAVL_TYPE(prefix,name)  prefix ## KAVLOU32 ## name
+#define KAVL_INT(name)          KAVLOU32INT ## name
+#define KAVL_DECL(rettype)      K_DECL_INLINE(rettype)
+
+#include <k/kAvlTmpl/kAvlBase.h>
+#include <k/kAvlTmpl/kAvlDoWithAll.h>
+#include <k/kAvlTmpl/kAvlEnum.h>
+#include <k/kAvlTmpl/kAvlGet.h>
+#include <k/kAvlTmpl/kAvlGetBestFit.h>
+#include <k/kAvlTmpl/kAvlGetWithParent.h>
+#include <k/kAvlTmpl/kAvlRemove2.h>
+#include <k/kAvlTmpl/kAvlRemoveBestFit.h>
+#include <k/kAvlTmpl/kAvlUndef.h>
+
+#endif
+
+
Index: /trunk/include/k/kAvlrU32.h
===================================================================
--- /trunk/include/k/kAvlrU32.h	(revision 2)
+++ /trunk/include/k/kAvlrU32.h	(revision 2)
@@ -0,0 +1,67 @@
+/* $Id$ */
+/** @file
+ * kAvl - AVL Tree Implementation, KU32 key ranges.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___k_kAvlrU32_h___
+#define ___k_kAvlrU32_h___
+
+typedef struct KAVLRU32
+{
+    KU32                u32Start;
+    KU32                u32Last;
+    struct KAVLRU32    *mpLeft;
+    struct KAVLRU32    *mpRight;
+    KU8                 mHeight;
+} KAVLRU32, *PKAVLRU32, **PPKAVLRU32;
+
+#define mKey                    u32Start
+#define mKeyLast                u32Last
+
+/*#define KAVL_EQUAL_ALLOWED*/
+#define KAVL_CHECK_FOR_EQUAL_INSERT
+#define KAVL_MAX_STACK          32
+#define KAVL_RANGE
+/*#define KAVL_OFFSET */
+#define KAVL_STD_KEY_COMP
+#define KAVLKEY                 KU32
+#define KAVLNODE                KAVLRU32
+#define KAVL_FN(name)           kAvlrU32 ## name
+#define KAVL_TYPE(prefix,name)  prefix ## KAVLRU32 ## name
+#define KAVL_INT(name)          KAVLRU32INT ## name
+#define KAVL_DECL(rettype)      K_DECL_INLINE(rettype)
+
+#include <k/kAvlTmpl/kAvlBase.h>
+#include <k/kAvlTmpl/kAvlDoWithAll.h>
+#include <k/kAvlTmpl/kAvlEnum.h>
+#include <k/kAvlTmpl/kAvlGet.h>
+#include <k/kAvlTmpl/kAvlGetBestFit.h>
+#include <k/kAvlTmpl/kAvlGetWithParent.h>
+#include <k/kAvlTmpl/kAvlRemove2.h>
+#include <k/kAvlTmpl/kAvlRemoveBestFit.h>
+#include <k/kAvlTmpl/kAvlUndef.h>
+
+#endif
+
+
Index: /trunk/include/k/kCpu.h
===================================================================
--- /trunk/include/k/kCpu.h	(revision 2)
+++ /trunk/include/k/kCpu.h	(revision 2)
@@ -0,0 +1,64 @@
+/* $Id$ */
+/** @file
+ * kCpu - The CPU and Architecture API.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___k_kCpu_h___
+#define ___k_kCpu_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kCpus.h>
+
+
+/** @defgroup grp_kCpu      kCpu  - The CPU And Architecture API
+ * @{
+ */
+
+/** @def KCPU_DECL
+ * Declares a kCpu function according to build context.
+ * @param type          The return type.
+ */
+#if defined(KCPU_BUILDING_DYNAMIC)
+# define KCPU_DECL(type)        K_DECL_EXPORT(type)
+#elif defined(KCPU_BUILT_DYNAMIC)
+# define KCPU_DECL(type)        K_DECL_IMPORT(type)
+#else
+# define KCPU_DECL(type)        type
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KCPU_DECL(void) kCpuGetArchAndCpu(PKCPUARCH penmArch, PKCPU penmCpu);
+KCPU_DECL(int)  kCpuCompare(KCPUARCH enmCodeArch, KCPU enmCodeCpu, KCPUARCH enmArch, KCPU enmCpu);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
Index: /trunk/include/k/kCpus.h
===================================================================
--- /trunk/include/k/kCpus.h	(revision 2)
+++ /trunk/include/k/kCpus.h	(revision 2)
@@ -0,0 +1,153 @@
+/* $Id$ */
+/** @file
+ * kCpus - CPU Identifiers.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___k_kCpus_h___
+#define ___k_kCpus_h___
+
+/** @defgroup grp_kCpus     kCpus - CPU Identifiers
+ * @see the kCpu API for functions operating on the CPU type.
+ * @{
+ */
+
+/**
+ * CPU Architectures.
+ *
+ * The constants used by this enum has the same values as
+ * the K_ARCH_* #defines defined by k/kDefs.h.
+ */
+typedef enum KCPUARCH
+{
+    /** @copydoc K_ARCH_UNKNOWN */
+    KCPUARCH_UNKNOWN = K_ARCH_UNKNOWN,
+    /** @copydoc K_ARCH_X86_16 */
+    KCPUARCH_X86_16 = K_ARCH_X86_16,
+    /** @copydoc K_ARCH_X86_32 */
+    KCPUARCH_X86_32 = K_ARCH_X86_32,
+    /** @copydoc K_ARCH_AMD64 */
+    KCPUARCH_AMD64 = K_ARCH_AMD64,
+    /** @copydoc K_ARCH_IA64 */
+    KCPUARCH_IA64 = K_ARCH_IA64,
+    /** @copydoc K_ARCH_ALPHA */
+    KCPUARCH_ALPHA = K_ARCH_ALPHA,
+    /** @copydoc K_ARCH_ALPHA_32 */
+    KCPUARCH_ALPHA_32 = K_ARCH_ALPHA_32,
+    /** @copydoc K_ARCH_ARM_32 */
+    KCPUARCH_ARM_32 = K_ARCH_ARM_32,
+    /** @copydoc K_ARCH_ARM_64 */
+    KCPUARCH_ARM_64 = K_ARCH_ARM_64,
+    /** @copydoc K_ARCH_MIPS_32 */
+    KCPUARCH_MIPS_32 = K_ARCH_MIPS_32,
+    /** @copydoc K_ARCH_MIPS_64 */
+    KCPUARCH_MIPS_64 = K_ARCH_MIPS_64,
+    /** @copydoc K_ARCH_POWERPC_32 */
+    KCPUARCH_POWERPC_32 = K_ARCH_POWERPC_32,
+    /** @copydoc K_ARCH_POWERPC_64 */
+    KCPUARCH_POWERPC_64 = K_ARCH_POWERPC_64,
+    /** @copydoc K_ARCH_SPARC_32 */
+    KCPUARCH_SPARC_32 = K_ARCH_SPARC_32,
+    /** @copydoc K_ARCH_SPARC_64 */
+    KCPUARCH_SPARC_64 = K_ARCH_SPARC_64,
+
+    /** Hack to blow the type up to 32-bit. */
+    KCPUARCH_32BIT_HACK = 0x7fffffff
+} KCPUARCH;
+
+/** Pointer to a CPU architecture type. */
+typedef KCPUARCH *PKCPUARCH;
+/** Pointer to a const CPU architecture type. */
+typedef const KCPUARCH *PCKCPUARCH;
+
+
+/**
+ * CPU models.
+ */
+typedef enum KCPU
+{
+    /** The usual invalid cpu. */
+    KCPU_INVALID = 0,
+
+    /** @name K_ARCH_X86_16
+     * @{ */
+    KCPU_I8086,
+    KCPU_I8088,
+    KCPU_I80186,
+    KCPU_I80286,
+    KCPU_I386_16,
+    KCPU_I486_16,
+    KCPU_I486SX_16,
+    KCPU_I586_16,
+    KCPU_I686_16,
+    KCPU_P4_16,
+    KCPU_CORE2_16,
+    KCPU_K6_16,
+    KCPU_K7_16,
+    KCPU_K8_16,
+    KCPU_FIRST_X86_16 = KCPU_I8086,
+    KCPU_LAST_X86_16 = KCPU_K8_16,
+    /** @} */
+
+    /** @name K_ARCH_X86_32
+     * @{ */
+    KCPU_X86_32_BLEND,
+    KCPU_I386,
+    KCPU_I486,
+    KCPU_I486SX,
+    KCPU_I586,
+    KCPU_I686,
+    KCPU_P4,
+    KCPU_CORE2_32,
+    KCPU_K6,
+    KCPU_K7,
+    KCPU_K8_32,
+    KCPU_FIRST_X86_32 = KCPU_I386,
+    KCPU_LAST_X86_32 = KCPU_K8_32,
+    /** @} */
+
+    /** @name K_ARCH_AMD64
+     * @{ */
+    KCPU_AMD64_BLEND,
+    KCPU_K8,
+    KCPU_P4_64,
+    KCPU_CORE2,
+    KCPU_FIRST_AMD64 = KCPU_K8,
+    KCPU_LAST_AMD64 = KCPU_CORE2,
+    /** @} */
+
+    /** The end of the valid cpu values (exclusive). */
+    KCPU_END,
+    /** Hack to blow the type up to 32-bit. */
+    KCPU_32BIT_HACK = 0x7fffffff
+} KCPU;
+
+/** Pointer to a CPU type. */
+typedef KCPU *PKCPU;
+/** Pointer to a const CPU type. */
+typedef const KCPU *PCKCPU;
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kDbg.h
===================================================================
--- /trunk/include/k/kDbg.h	(revision 2)
+++ /trunk/include/k/kDbg.h	(revision 2)
@@ -0,0 +1,237 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with This program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kDbg_h___
+#define ___k_kDbg_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kRdr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup grp_kDbg      Debug Info Reader
+ * @{
+ */
+
+/** @def KDBG_DECL
+ * Declares a kDbg function according to build context.
+ * @param type          The return type.
+ */
+#if defined(KDBG_BUILDING_DYNAMIC)
+# define KDBG_DECL(type)        K_DECL_EXPORT(type)
+#elif defined(KDBG_BUILT_DYNAMIC)
+# define KDBG_DECL(type)        K_DECL_IMPORT(type)
+#else
+# define KDBG_DECL(type)        type
+#endif
+
+
+/** The kDbg address type. */
+typedef KU64                    KDBGADDR;
+/** Pointer to a kDbg address. */
+typedef KDBGADDR               *PKDBGADDR;
+/** Pointer to a const kDbg address. */
+typedef const KDBGADDR         *PCKDBGADDR;
+/** @def KDBGADDR_PRI
+ * printf format type. */
+#define KDBGADDR_PRI            KX64_PRI
+/** @def KDBGADDR_MAX
+ * Max kDbg address value. */
+#define KDBGADDR_MAX            KU64_C(0xfffffffffffffffe)
+/** @def KDBGADDR_C
+ * kDbg address constant.
+ * @param c         The constant value. */
+#define KDBGADDR_C(c)           KU64_C(c)
+/** NIL address. */
+#define NIL_KDBGADDR            KU64_MAX
+
+
+/** @name   Special Segments
+ * @{ */
+/** Relative Virtual Address.
+ * The specified offset is relative to the image base. The image base is the lowest memory
+ * address used by the image when loaded with the address assignments indicated in the image. */
+#define KDBGSEG_RVA             (-1)
+/** Absolute segment. The offset isn't relative to anything. */
+#define KDBGSEG_ABS             (-2)
+/** @} */
+
+
+/** The max filename path length used by the debug reader. */
+#define KDBG_PATH_MAX           260
+
+/**
+ * Line number details.
+ */
+typedef struct KDBGLINE
+{
+    /** The relative virtual address. */
+    KDBGADDR    RVA;
+    /** The offset into the segment. */
+    KDBGADDR    offSegment;
+    /** The segment number. */
+    KI32        iSegment;
+    /** The Line number. */
+    KU32        iLine;
+    /** The actual size of this structure. */
+    KU16        cbSelf;
+    /** The length of the filename. */
+    KU16        cchFile;
+    /** The name of the file this line number relates to. */
+    char        szFile[KDBG_PATH_MAX];
+} KDBGLINE;
+/** Pointer to line number details. */
+typedef KDBGLINE *PKDBGLINE;
+/** Pointer to const line number details. */
+typedef const KDBGLINE *PCKDBGLINE;
+/** Pointer to a pointer to line number details. */
+typedef PKDBGLINE *PPKDBGLINE;
+
+/**
+ * Duplicates a line number.
+ *
+ * To save heap space, the returned line number will not own more heap space
+ * than it strictly need to. So, it's not possible to append stuff to the symbol
+ * or anything of that kind.
+ *
+ * @returns Pointer to the duplicate.
+ *          This must be freed using RTDbgSymbolFree().
+ * @param   pLine       The line number to be duplicated.
+ */
+KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine);
+
+/**
+ * Frees a line number obtained from the RTDbg API.
+ *
+ * @returns VINF_SUCCESS on success.
+ * @returns KERR_INVALID_POINTER if a NULL pointer or an !KDBG_VALID_PTR() is passed in.
+ *
+ * @param   pLine       The line number to be freed.
+ */
+KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine);
+
+
+/** @name Symbol Flags.
+ * @{ */
+/** The symbol is weak. */
+#define KDBGSYM_FLAGS_WEAK      KU32_C(0x00000000)
+/** The symbol is absolute.
+ * (This also indicated by the segment number.) */
+#define KDBGSYM_FLAGS_ABS       KU32_C(0x00000001)
+/** The symbol is exported. */
+#define KDBGSYM_FLAGS_EXPORTED  KU32_C(0x00000002)
+/** The symbol is a function/method/procedure/whatever-executable-code. */
+#define KDBGSYM_FLAGS_CODE      KU32_C(0x00000004)
+/** The symbol is some kind of data. */
+#define KDBGSYM_FLAGS_DATA      KU32_C(0x00000008)
+/** @} */
+
+/** The max symbol name length used by the debug reader. */
+#define KDBG_SYMBOL_MAX         384
+
+/**
+ * Symbol details.
+ */
+typedef struct KDBGSYMBOL
+{
+    /** The adddress of this symbol in the relevant space.
+     * This is NIL_KDBGADDR unless the information was
+     * returned by a kDbgSpace API. */
+    KDBGADDR    Address;
+    /** The relative virtual address. */
+    KDBGADDR    RVA;
+    /** The symbol size.
+     * This is not a reliable field, it could be a bad guess. Ignore if zero. */
+    KDBGADDR    cb;
+    /** The offset into the segment. */
+    KDBGADDR    offSegment;
+    /** The segment number. */
+    KI32        iSegment;
+    /** The symbol flags. */
+    KU32        fFlags;
+/** @todo type info. */
+    /** The actual size of this structure. */
+    KU16        cbSelf;
+    /** The length of the symbol name. */
+    KU16        cchName;
+    /** The symbol name. */
+    char        szName[KDBG_SYMBOL_MAX];
+} KDBGSYMBOL;
+/** Pointer to symbol details. */
+typedef KDBGSYMBOL *PKDBGSYMBOL;
+/** Pointer to const symbol details. */
+typedef const KDBGSYMBOL *PCKDBGSYMBOL;
+/** Pointer to a pointer to symbol details. */
+typedef PKDBGSYMBOL *PPKDBGSYMBOL;
+
+/**
+ * Duplicates a symbol.
+ *
+ * To save heap space, the returned symbol will not own more heap space than
+ * it strictly need to. So, it's not possible to append stuff to the symbol
+ * or anything of that kind.
+ *
+ * @returns Pointer to the duplicate.
+ *          This must be freed using kDbgSymbolFree().
+ * @param   pSymbol     The symbol to be freed.
+ */
+KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol);
+
+/**
+ * Frees a symbol obtained from the kDbg API.
+ *
+ * @returns VINF_SUCCESS on success.
+ * @returns KERR_INVALID_POINTER if a NULL pointer or an !KDBG_VALID_PTR() is passed in.
+ *
+ * @param   pSymbol     The symbol to be freed.
+ */
+KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol);
+
+
+/** Pointer to a debug module. */
+typedef struct KDBGMOD *PKDBGMOD;
+/** Pointer to a debug module pointer. */
+typedef PKDBGMOD *PPKDBGMOD;
+
+
+KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod);
+KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod);
+KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod);
+KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod);
+KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym);
+KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym);
+KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine);
+KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine);
+
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /trunk/include/k/kDbgAll.h
===================================================================
--- /trunk/include/k/kDbgAll.h	(revision 2)
+++ /trunk/include/k/kDbgAll.h	(revision 2)
@@ -0,0 +1,162 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Read, All Details and Dependencies Included.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with This program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kDbgAll_h___
+#define ___k_kDbgAll_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kRdr.h>
+#include <k/kLdr.h>
+#include <k/kDbg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup grp_kDbgAll   All
+ * @addtogroup grp_kDbg
+ * @{
+ */
+
+/**
+ * The debug module method table.
+ */
+typedef struct KDBGMODOPS
+{
+    /** The name of the reader. */
+    const char *pszName;
+
+    /** Pointer to the next debug module readers.
+     * This is only used for dynamically registered readers. */
+    struct KDBGMODOPS  *pNext;
+
+    /**
+     * Tries to open the module.
+     *
+     * @returns 0 on success, KDBG_ERR on failure.
+     * @param   ppMod           Where to store the module that's been opened.
+     * @param   pRdr            The file provider.
+     * @param   fCloseRdrs       Whether the reader should be closed or not when the module is destroyed.
+     * @param   off             The file offset of the debug info. This is 0 if there isn't
+     *                          any specfic debug info section and the reader should start
+     *                          looking for debug info at the start of the file.
+     * @param   cb              The size of the debug info in the file. INT64_MAX if we don't
+     *                          know or there isn't any particular debug info section in the file.
+     * @param   pLdrMod         The associated loader module. This can be NULL.
+     */
+    int (*pfnOpen)(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod);
+
+    /**
+     * Closes the module.
+     *
+     * This should free all resources associated with the module
+     * except the pMod which is freed by the caller.
+     *
+     * @returns IPRT status code.
+     * @param   pMod        The module.
+     */
+    int (*pfnClose)(PKDBGMOD pMod);
+
+    /**
+     * Gets a symbol by segment:offset.
+     * This will be approximated to the nearest symbol if there is no exact match.
+     *
+     * @returns 0 on success. KLDR_ERR_* on failure.
+     * @param   pMod        The module.
+     * @param   iSegment    The segment this offset is relative to.
+     *                      The -1 segment is special, it means that the addres is relative to
+     *                      the image base. The image base is where the first bit of the image
+     *                      is mapped during load.
+     * @param   off         The offset into the segment.
+     * @param   pSym        Where to store the symbol details.
+     */
+    int (*pfnQuerySymbol)(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym);
+
+    /**
+     * Gets a line number entry by segment:offset.
+     * This will be approximated to the nearest line number there is no exact match.
+     *
+     * @returns 0 on success. KLDR_ERR_* on failure.
+     * @param   pMod        The module.
+     * @param   iSegment    The segment this offset is relative to.
+     *                      The -1 segment is special, it means that the addres is relative to
+     *                      the image base. The image base is where the first bit of the image
+     *                      is mapped during load.
+     * @param   off         The offset into the segment.
+     * @param   pLine       Where to store the line number details.
+     */
+    int (*pfnQueryLine)(PKDBGMOD pMod, KI32 iSegment, KDBGADDR uOffset, PKDBGLINE pLine);
+
+    /** This is just to make sure you've initialized all the fields.
+     * Must be identical to pszName. */
+    const char *pszName2;
+} KDBGMODOPS;
+/** Pointer to a module method table. */
+typedef KDBGMODOPS *PKDBGMODOPS;
+/** Pointer to a const module method table. */
+typedef const KDBGMODOPS *PCKDBGMODOPS;
+
+/**
+ * Register a debug module reader with the kDbgModule component.
+ *
+ * Dynamically registered readers are kept in FIFO order, and external
+ * readers will be tried after the builtin ones.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pOps is missing bits.
+ * @returns KERR_INVALID_PARAMETER if pOps is already in the list.
+ * @param   pOps        The reader method table, kDbg takes owner ship of
+ *                      this. This must be writeable as the pNext pointer
+ *                      will be update. It must also stick around for as
+ *                      long as kDbg is in use.
+ */
+KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps);
+
+
+
+/**
+ * Internal representation of a debug module.
+ */
+typedef struct KDBGMOD
+{
+    /** Magic value (KDBGMOD_MAGIC). */
+    KI32            u32Magic;
+    /** Pointer to the method table. */
+    PCKDBGMODOPS    pOps;
+    /** The file provider for the file containing the debug info. */
+    PKRDR           pRdr;
+    /** Whether or not to close pRdr. */
+    KBOOL           fCloseRdr;
+    /** The associated kLdr module. This may be NULL. */
+    PKLDRMOD        pLdrMod;
+} KDBGMOD;
+
+/** @}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /trunk/include/k/kDbgBase.h
===================================================================
--- /trunk/include/k/kDbgBase.h	(revision 2)
+++ /trunk/include/k/kDbgBase.h	(revision 2)
@@ -0,0 +1,245 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, Base Definitions and Typedefs.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird@anduin.net>
+ *
+ *
+ * This file is part of kDbg.
+ *
+ * kDbg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kDbg 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kDbg; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___kDbgBase_h___
+#define ___kDbgBase_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+
+
+/** @defgroup grp_kDbgBase  kDbgBase - Base Definitions And Typedefs
+ * @{ */
+
+/*
+ * kDbg depend on size_t, [u]intNN_t, [u]intptr_t and some related constants.
+ * If KDBG_ALREADY_INCLUDED_STD_TYPES or KCOMMON_ALREADY_INCLUDED_STD_TYPES
+ * is defined, these has already been defined.
+ */
+#if !defined(KDBG_ALREADY_INCLUDED_STD_TYPES) && !defined(KCOMMON_ALREADY_INCLUDED_STD_TYPES)
+# define KCOMMON_ALREADY_INCLUDED_STD_TYPES 1
+# include <sys/types.h>
+# include <stddef.h>
+# ifdef _MSC_VER
+   typedef signed char          int8_t;
+   typedef unsigned char        uint8_t;
+   typedef signed short         int16_t;
+   typedef unsigned short       uint16_t;
+   typedef signed int           int32_t;
+   typedef unsigned int         uint32_t;
+   typedef signed __int64       int64_t;
+   typedef unsigned __int64     uint64_t;
+   typedef int64_t              intmax_t;
+   typedef uint64_t             uintmax_t;
+#  define UINT8_C(c)            (c)
+#  define UINT16_C(c)           (c)
+#  define UINT32_C(c)           (c ## U)
+#  define UINT64_C(c)           (c ## ULL)
+#  define INT8_C(c)             (c)
+#  define INT16_C(c)            (c)
+#  define INT32_C(c)            (c)
+#  define INT64_C(c)            (c ## LL)
+#  define INT8_MIN              (INT8_C(-0x7f) - 1)
+#  define INT16_MIN             (INT16_C(-0x7fff) - 1)
+#  define INT32_MIN             (INT32_C(-0x7fffffff) - 1)
+#  define INT64_MIN             (INT64_C(-0x7fffffffffffffff) - 1)
+#  define INT8_MAX              INT8_C(0x7f)
+#  define INT16_MAX             INT16_C(0x7fff)
+#  define INT32_MAX             INT32_C(0x7fffffff)
+#  define INT64_MAX             INT64_C(0x7fffffffffffffff)
+#  define UINT8_MAX             UINT8_C(0xff)
+#  define UINT16_MAX            UINT16_C(0xffff)
+#  define UINT32_MAX            UINT32_C(0xffffffff)
+#  define UINT64_MAX            UINT64_C(0xffffffffffffffff)
+# else
+#  include <stdint.h>
+# endif
+#endif /* !KDBG_ALREADY_INCLUDED_STD_TYPES && !KCOMMON_ALREADY_INCLUDED_STD_TYPES */
+
+
+/** @def KDBG_CALL
+ * The calling convention used by the kDbg functions. */
+#if defined(_MSC_VER) || defined(__OS2__)
+# define KDBG_CALL  __cdecl
+#else
+# define KDBG_CALL
+#endif
+
+#ifdef __DOXYGEN__
+/** @def KDBG_BUILDING
+ * Define KDBG_BUILDING to indicate that kDbg is being built.
+ */
+# define KDBG_BUILDING
+/** @def KDBG_RESIDES_IN_DLL
+ * Define KDBG_RESIDES_IN_DLL to indicate that kDbg resides in a DLL.
+ */
+# define KDBG_RESIDES_IN_DLL
+#endif
+
+/** @def KDBG_DECL
+ * Macro for defining public functions. */
+#if defined(KDBG_RESIDES_IN_DLL) \
+ && (defined(_MSC_VER) || defined(__OS2__))
+# ifdef KDBG_BUILDING
+#  define KDBG_DECL(type) __declspec(dllexport) type
+# else
+#  define KDBG_DECL(type) __declspec(dllimport) type
+# endif
+#else
+# define KDBG_DECL(type) type
+#endif
+
+/** @def KDBG_INLINE
+ * Macro for defining an inline function. */
+#ifdef __cplusplus
+# if defined(__GNUC__)
+#  define KDBG_INLINE(type) static inline type
+# else
+#  define KDBG_INLINE(type) inline type
+# endif
+#else
+# if defined(__GNUC__)
+#  define KDBG_INLINE(type) static __inline__ type
+# elif defined(_MSC_VER)
+#  define KDBG_INLINE(type) _inline type
+# else
+#  error "Port me"
+# endif
+#endif
+
+
+/** The kDbg address type. */
+typedef uint64_t KDBGADDR;
+/** Pointer to a kLdr address. */
+typedef KDBGADDR *PKDBGADDR;
+/** Pointer to a const kLdr address. */
+typedef const KDBGADDR *PCKDBGADDR;
+
+/** NIL address. */
+#define NIL_KDBGADDR    (~(uint64_t)0)
+
+/** @def PRI_KDBGADDR
+ * printf format type. */
+#ifdef _MSC_VER
+# define PRI_KDBGADDR    "I64x"
+#else
+# define PRI_KDBGADDR    "llx"
+#endif
+
+
+/** Get the minimum of two values. */
+#define KDBG_MIN(a, b)              ((a) <= (b) ? (a) : (b))
+/** Get the maximum of two values. */
+#define KDBG_MAX(a, b)              ((a) >= (b) ? (a) : (b))
+/** Calculate the offset of a structure member. */
+#define KDBG_OFFSETOF(strct, memb)  ( (size_t)( &((strct *)0)->memb ) )
+/** Align a size_t value. */
+#define KDBG_ALIGN_Z(val, align)    ( ((val) + ((align) - 1)) & ~(size_t)((align) - 1) )
+/** Align a void * value. */
+#define KDBG_ALIGN_P(pv, align)     ( (void *)( ((uintptr_t)(pv) + ((align) - 1)) & ~(uintptr_t)((align) - 1) ) )
+/** Align a size_t value. */
+#define KDBG_ALIGN_ADDR(val, align) ( ((val) + ((align) - 1)) & ~(KDBGADDR)((align) - 1) )
+/** Number of elements in an array. */
+#define KDBG_ELEMENTS(a)            ( sizeof(a) / sizeof((a)[0]) )
+/** @def KDBG_VALID_PTR
+ * Checks if the specified pointer is a valid address or not. */
+#define KDBG_VALID_PTR(ptr)         ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U )
+
+
+/** @def KDBG_LITTLE_ENDIAN
+ * The kDbg build is for a little endian target. */
+/** @def KDBG_BIG_ENDIAN
+ * The kDbg build is for a big endian target. */
+#if !defined(KDBG_LITTLE_ENDIAN) && !defined(KDBG_BIG_ENDIAN)
+# define KDBG_LITTLE_ENDIAN
+#endif
+#ifdef __DOXYGEN__
+# define KDBG_BIG_ENDIAN
+#endif
+
+
+/** @name Endian Conversion
+ * @{ */
+
+/** @def KDBG_E2E_U16
+ * Convert the endian of an unsigned 16-bit value. */
+# define KDBG_E2E_U16(u16)      ( (uint16_t) (((u16) >> 8) | ((u16) << 8)) )
+/** @def KDBG_E2E_U32
+ * Convert the endian of an unsigned 32-bit value. */
+# define KDBG_E2E_U32(u32)      (   ( ((u32) & UINT32_C(0xff000000)) >> 24 ) \
+                                  | ( ((u32) & UINT32_C(0x00ff0000)) >>  8 ) \
+                                  | ( ((u32) & UINT32_C(0x0000ff00)) <<  8 ) \
+                                  | ( ((u32) & UINT32_C(0x000000ff)) << 24 ) \
+                                )
+/** @def KDBG_E2E_U64
+ * Convert the endian of an unsigned 64-bit value. */
+# define KDBG_E2E_U64(u64)      (   ( ((u64) & UINT64_C(0xff00000000000000)) >> 56 ) \
+                                  | ( ((u64) & UINT64_C(0x00ff000000000000)) >> 40 ) \
+                                  | ( ((u64) & UINT64_C(0x0000ff0000000000)) >> 24 ) \
+                                  | ( ((u64) & UINT64_C(0x000000ff00000000)) >>  8 ) \
+                                  | ( ((u64) & UINT64_C(0x00000000ff000000)) <<  8 ) \
+                                  | ( ((u64) & UINT64_C(0x0000000000ff0000)) << 24 ) \
+                                  | ( ((u64) & UINT64_C(0x000000000000ff00)) << 40 ) \
+                                  | ( ((u64) & UINT64_C(0x00000000000000ff)) << 56 ) \
+                                )
+
+/** @def KDBG_LE2H_U16
+ * Unsigned 16-bit little-endian to host endian. */
+/** @def KDBG_LE2H_U32
+ * Unsigned 32-bit little-endian to host endian. */
+/** @def KDBG_LE2H_U64
+ * Unsigned 64-bit little-endian to host endian. */
+/** @def KDBG_BE2H_U16
+ * Unsigned 16-bit big-endian to host endian. */
+/** @def KDBG_BE2H_U32
+ * Unsigned 32-bit big-endian to host endian. */
+/** @def KDBG_BE2H_U64
+ * Unsigned 64-bit big-endian to host endian. */
+#ifdef KDBG_LITTLE_ENDIAN
+# define KDBG_LE2H_U16(u16)  ((uint16_t)(u16))
+# define KDBG_LE2H_U32(u32)  ((uint32_t)(u32))
+# define KDBG_LE2H_U64(u64)  ((uint32_t)(u32))
+# define KDBG_BE2H_U16(u16)  KDBG_E2E_U16(u16)
+# define KDBG_BE2H_U32(u32)  KDBG_E2E_U32(u32)
+# define KDBG_BE2H_U64(u64)  KDBG_E2E_U64(u64)
+#elif defined(KDBG_BIG_ENDIAN)
+# define KDBG_LE2H_U16(u16)  KDBG_E2E_U16(u16)
+# define KDBG_LE2H_U32(u32)  KDBG_E2E_U32(u32)
+# define KDBG_LE2H_U32(u64)  KDBG_E2E_U64(u64)
+# define KDBG_BE2H_U16(u16)  ((uint16_t)(u16))
+# define KDBG_BE2H_U32(u32)  ((uint32_t)(u32))
+# define KDBG_BE2H_U64(u64)  ((uint32_t)(u32))
+#else
+# error "KDBG_BIG_ENDIAN or KDBG_LITTLE_ENDIAN is supposed to be defined."
+#endif
+
+/** @} */
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kDefs.h
===================================================================
--- /trunk/include/k/kDefs.h	(revision 2)
+++ /trunk/include/k/kDefs.h	(revision 2)
@@ -0,0 +1,492 @@
+/* $Id$ */
+/** @file
+ *
+ * kTypes - Defines and Macros.
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ *
+ * This file is part of k*.
+ *
+ * k* is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * k* 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with k*; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kDefs_h___
+#define ___k_kDefs_h___
+
+/** @defgroup grp_kDefs  kDefs - Defines and Macros
+ * @{ */
+
+/** @name Operative System Identifiers.
+ * These are the value that the K_OS \#define can take.
+ * @{
+ */
+/** Unknown OS. */
+#define K_OS_UNKNOWN    0
+/** Darwin - aka Mac OS X. */
+#define K_OS_DARWIN     1
+/** FreeBSD. */
+#define K_OS_FREEBSD    2
+/** Linux. */
+#define K_OS_LINUX      3
+/** NetBSD. */
+#define K_OS_NETBSD     4
+/** NT (native). */
+#define K_OS_NT         5
+/** OpenBSD*/
+#define K_OS_OPENBSD    6
+/** OS/2 */
+#define K_OS_OS2        7
+/** Solaris */
+#define K_OS_SOLARIS    8
+/** Windows. */
+#define K_OS_WINDOWS    9
+/** The max K_OS_* value (exclusive). */
+#define K_OS_MAX        10
+/** @} */
+
+/** @def K_OS
+ * Indicates which OS we're targetting. It's a \#define with is
+ * assigned one of the K_OS_* defines above.
+ *
+ * So to test if we're on FreeBSD do the following:
+ * @code
+ *  #if K_OS == K_OS_FREEBSD
+ *  some_funky_freebsd_specific_stuff();
+ *  #endif
+ * @endcode
+ */
+#ifndef K_OS
+# if defined(__APPLE__)
+#  define K_OS      K_OS_DARWIN
+# elif defined(__FreeBSD__) /*??*/
+#  define K_OS      K_OS_FREEBSD
+# elif defined(__gnu_linux__)
+#  define K_OS      K_OS_LINUX
+# elif defined(__NetBSD__) /*??*/
+#  define K_OS      K_OS_NETBSD
+# elif defined(__OpenBSD__) /*??*/
+#  define K_OS      K_OS_OPENBSD
+# elif defined(__OS2__)
+#  define K_OS      K_OS_OS2
+# elif defined(__SunOrSomething__)
+#  define K_OS      K_OS_SOLARIS
+# elif defined(_WIN32) || defined(_WIN64)
+#  define K_OS      K_OS_WINDOWS
+# else
+#  error "Port Me"
+# endif
+#endif
+#if K_OS < K_OS_UNKNOWN || K_OS >= K_OS_MAX
+# error "Invalid K_OS value."
+#endif
+
+
+
+/** @name   Architecture bit width.
+ * @{ */
+#define K_ARCH_BIT_8            0x0100  /**< 8-bit */
+#define K_ARCH_BIT_16           0x0200  /**< 16-bit */
+#define K_ARCH_BIT_32           0x0400  /**< 32-bit */
+#define K_ARCH_BIT_64           0x0800  /**< 64-bit */
+#define K_ARCH_BIT_128          0x1000  /**< 128-bit */
+#define K_ARCH_BIT_MASK         0x1f00  /**< The bit mask. */
+#define K_ARCH_BIT_SHIFT        5       /**< Shift count for producing the width in bits. */
+#define K_ARCH_BYTE_SHIFT       8       /**< Shift count for producing the width in bytes. */
+/** @} */
+
+/** @name   Architecture Endianness.
+ * @{ */
+#define K_ARCH_END_LITTLE       0x2000  /**< Little-endian. */
+#define K_ARCH_END_BIG          0x4000  /**< Big-endian. */
+#define K_ARCH_END_BI           0x6000  /**< Bi-endian, can be switched. */
+#define K_ARCH_END_MASK         0x6000  /**< The endian mask. */
+#define K_ARCH_END_SHIFT        13      /**< Shift count for converting between this K_ENDIAN_*. */
+/** @} */
+
+/** @name Architecture Identifiers.
+ * These are the value that the K_ARCH \#define can take.
+ *@{ */
+/** Unknown CPU architecture. */
+#define K_ARCH_UNKNOWN          ( 0 )
+/** Clone or Intel 16-bit x86. */
+#define K_ARCH_X86_16           ( 1 | K_ARCH_BIT_16 | K_ARCH_END_LITTLE)
+/** Clone or Intel 32-bit x86. */
+#define K_ARCH_X86_32           ( 2 | K_ARCH_BIT_32 | K_ARCH_END_LITTLE)
+/** AMD64 (including clones). */
+#define K_ARCH_AMD64            ( 3 | K_ARCH_BIT_64 | K_ARCH_END_LITTLE)
+/** Itanic (64-bit). */
+#define K_ARCH_IA64             ( 4 | K_ARCH_BIT_64 | K_ARCH_END_BI)
+/** ALPHA (64-bit). */
+#define K_ARCH_ALPHA            ( 5 | K_ARCH_BIT_64 | K_ARCH_END_BI)
+/** ALPHA limited to 32-bit. */
+#define K_ARCH_ALPHA_32         ( 6 | K_ARCH_BIT_32 | K_ARCH_END_BI)
+/** 32-bit ARM. */
+#define K_ARCH_ARM_32           ( 7 | K_ARCH_BIT_32 | K_ARCH_END_BI)
+/** 64-bit ARM. */
+#define K_ARCH_ARM_64           ( 8 | K_ARCH_BIT_64 | K_ARCH_END_BI)
+/** 32-bit MIPS. */
+#define K_ARCH_MIPS_32          ( 9 | K_ARCH_BIT_32 | K_ARCH_END_BI)
+/** 64-bit MIPS. */
+#define K_ARCH_MIPS_64          (10 | K_ARCH_BIT_64 | K_ARCH_END_BI)
+/** 32-bit PowerPC. */
+#define K_ARCH_POWERPC_32       (11 | K_ARCH_BIT_32 | K_ARCH_END_BI)
+/** 64-bit PowerPC. */
+#define K_ARCH_POWERPC_64       (12 | K_ARCH_BIT_64 | K_ARCH_END_BI)
+/** 32-bit SPARC. */
+#define K_ARCH_SPARC_32         (13 | K_ARCH_BIT_32 | K_ARCH_END_BIG)
+/** 64-bit SPARC. */
+#define K_ARCH_SPARC_64         (14 | K_ARCH_BIT_64 | K_ARCH_END_BI)
+/** The end of the valid architecture values (exclusive). */
+#define K_ARCH_MAX              (15)
+/** @} */
+
+
+/** @def K_ARCH
+ * The value of this \#define indicates which architecture we're targetting.
+ */
+#ifndef K_ARCH
+  /* detection based on compiler defines. */
+# if defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_X64)
+#  define K_ARCH    K_ARCH_AMD64
+# elif defined(__i386__) || defined(__x86__) || defined(__X86__) || defined(_M_IX86)
+#  define K_ARCH    K_ARCH_X86_32
+# elif defined(__ia64__) || defined(__IA64__) || defined(_M_IA64)
+#  define K_ARCH    K_ARCH_IA64
+# else
+#  error "Port Me"
+# endif
+#else
+  /* validate the user specified value. */
+# if (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_8 \
+  && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_16 \
+  && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_32 \
+  && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_64 \
+  && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_128
+#  error "Invalid K_ARCH value (bit)"
+# endif
+# if (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_LITTLE \
+  && (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_BIG \
+  && (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_BI
+#  error "Invalid K_ARCH value (endian)"
+# endif
+# if (K_ARCH & ~(K_ARCH_BIT_MASK | K_ARCH_BIT_END_MASK)) < K_ARCH_UNKNOWN \
+  || (K_ARCH & ~(K_ARCH_BIT_MASK | K_ARCH_BIT_END_MASK)) >= K_ARCH_MAX
+#  error "Invalid K_ARCH value"
+# endif
+#endif
+
+/** @def K_ARCH_IS_VALID
+ * Check if the architecture identifier is valid.
+ * @param   arch            The K_ARCH_* define to examin.
+ */
+#define K_ARCH_IS_VALID(arch)   (   (   ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_8 \
+                                     || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_16 \
+                                     || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_32 \
+                                     || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_64 \
+                                     || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_128) \
+                                 && \
+                                    (   ((arch) & K_ARCH_END_MASK) == K_ARCH_END_LITTLE \
+                                     || ((arch) & K_ARCH_END_MASK) == K_ARCH_END_BIG \
+                                     || ((arch) & K_ARCH_END_MASK) == K_ARCH_END_BI) \
+                                 && \
+                                    (   ((arch) & ~(K_ARCH_BIT_MASK | K_ARCH_END_MASK)) >= K_ARCH_UNKNOWN \
+                                     && ((arch) & ~(K_ARCH_BIT_MASK | K_ARCH_END_MASK)) < K_ARCH_MAX) \
+                                )
+
+/** @def K_ARCH_BITS_EX
+ * Determin the architure byte width of the specified architecture.
+ * @param   arch            The K_ARCH_* define to examin.
+ */
+#define K_ARCH_BITS_EX(arch)    ( ((arch) & K_ARCH_BIT_MASK) >> K_ARCH_BIT_SHIFT )
+
+/** @def K_ARCH_BYTES_EX
+ * Determin the architure byte width of the specified architecture.
+ * @param   arch            The K_ARCH_* define to examin.
+ */
+#define K_ARCH_BYTES_EX(arch)   ( ((arch) & K_ARCH_BIT_MASK) >> K_ARCH_BYTE_SHIFT )
+
+/** @def K_ARCH_ENDIAN_EX
+ * Determin the K_ENDIAN value for the specified architecture.
+ * @param   arch            The K_ARCH_* define to examin.
+ */
+#define K_ARCH_ENDIAN_EX(arch)  ( ((arch) & K_ARCH_END_MASK) >> K_ARCH_END_SHIFT )
+
+/** @def K_ARCH_BITS
+ * Determin the target architure bit width.
+ */
+#define K_ARCH_BITS             K_ARCH_BITS_EX(K_ARCH)
+
+/** @def K_ARCH_BYTES
+ * Determin the target architure byte width.
+ */
+#define K_ARCH_BYTES            K_ARCH_BYTES_EX(K_ARCH)
+
+/** @def K_ARCH_ENDIAN
+ * Determin the target K_ENDIAN value.
+ */
+#define K_ARCH_ENDIAN           K_ARCH_ENDIAN_EX(K_ARCH)
+
+
+
+/** @name Endianness Identifiers.
+ * These are the value that the K_ENDIAN \#define can take.
+ * @{ */
+#define K_ENDIAN_LITTLE         1       /**< Little-endian. */
+#define K_ENDIAN_BIG            2       /**< Big-endian. */
+#define K_ENDIAN_BI             3       /**< Bi-endian, can be switched. Only used with K_ARCH. */
+/** @} */
+
+/** @def K_ENDIAN
+ * The value of this \#define indicates the target endianness.
+ *
+ * @remark  It's necessary to define this (or add the necessary dection here)
+ *          on bi-endian architectures.
+ */
+#ifndef K_ENDIAN
+  /* use K_ARCH if possible. */
+# if K_ARCH_END != K_ENDIAN_BI
+#  define K_ENDIAN K_ARCH_ENDIAN
+# else
+#  error "Port Me or define K_ENDIAN."
+# endif
+#else
+  /* validate the user defined value. */
+# if K_ENDIAN != K_ENDIAN_LITTLE
+  && K_ENDIAN != K_ENDIAN_BIG
+#  error "K_ENDIAN must either be defined as K_ENDIAN_LITTLE or as K_ENDIAN_BIG."
+# endif
+#endif
+
+/** @name Endian Conversion
+ * @{ */
+
+/** @def K_E2E_U16
+ * Convert the endian of an unsigned 16-bit value. */
+# define K_E2E_U16(u16)         ( (KU16) (((u16) >> 8) | ((u16) << 8)) )
+/** @def K_E2E_U32
+ * Convert the endian of an unsigned 32-bit value. */
+# define K_E2E_U32(u32)         (   ( ((u32) & KU32_C(0xff000000)) >> 24 ) \
+                                  | ( ((u32) & KU32_C(0x00ff0000)) >>  8 ) \
+                                  | ( ((u32) & KU32_C(0x0000ff00)) <<  8 ) \
+                                  | ( ((u32) & KU32_C(0x000000ff)) << 24 ) \
+                                )
+/** @def K_E2E_U64
+ * Convert the endian of an unsigned 64-bit value. */
+# define K_E2E_U64(u64)         (   ( ((u64) & KU64_C(0xff00000000000000)) >> 56 ) \
+                                  | ( ((u64) & KU64_C(0x00ff000000000000)) >> 40 ) \
+                                  | ( ((u64) & KU64_C(0x0000ff0000000000)) >> 24 ) \
+                                  | ( ((u64) & KU64_C(0x000000ff00000000)) >>  8 ) \
+                                  | ( ((u64) & KU64_C(0x00000000ff000000)) <<  8 ) \
+                                  | ( ((u64) & KU64_C(0x0000000000ff0000)) << 24 ) \
+                                  | ( ((u64) & KU64_C(0x000000000000ff00)) << 40 ) \
+                                  | ( ((u64) & KU64_C(0x00000000000000ff)) << 56 ) \
+                                )
+
+/** @def K_LE2H_U16
+ * Unsigned 16-bit little-endian to host endian. */
+/** @def K_LE2H_U32
+ * Unsigned 32-bit little-endian to host endian. */
+/** @def K_LE2H_U64
+ * Unsigned 64-bit little-endian to host endian. */
+/** @def K_BE2H_U16
+ * Unsigned 16-bit big-endian to host endian. */
+/** @def K_BE2H_U32
+ * Unsigned 32-bit big-endian to host endian. */
+/** @def K_BE2H_U64
+ * Unsigned 64-bit big-endian to host endian. */
+#if K_ENDIAN == K_ENDIAN_LITTLE
+# define K_LE2H_U16(u16)        ((KU16)(u16))
+# define K_LE2H_U32(u32)        ((KU32)(u32))
+# define K_LE2H_U64(u64)        ((KU64)(u32))
+# define K_BE2H_U16(u16)        K_E2E_U16(u16)
+# define K_BE2H_U32(u32)        K_E2E_U32(u32)
+# define K_BE2H_U64(u64)        K_E2E_U64(u64)
+#else
+# define K_LE2H_U16(u16)        K_E2E_U16(u16)
+# define K_LE2H_U32(u32)        K_E2E_U32(u32)
+# define K_LE2H_U32(u64)        K_E2E_U64(u64)
+# define K_BE2H_U16(u16)        ((KU16)(u16))
+# define K_BE2H_U32(u32)        ((KU32)(u32))
+# define K_BE2H_U64(u64)        ((KU64)(u32))
+#endif
+
+
+
+/** @def K_INLINE
+ * How to say 'inline' in both C and C++ dialects.
+ * @param   type        The return type.
+ */
+#ifdef __cplusplus
+# if defined(__GNUC__)
+#  define K_INLINE              static inline
+# else
+#  define K_INLINE              inline
+# endif
+#else
+# if defined(__GNUC__)
+#  define K_INLINE              static __inline__
+# elif defined(_MSC_VER)
+#  define K_INLINE              static _Inline
+# else
+#  error "Port Me"
+# endif
+#endif
+
+/** @def K_EXPORT
+ * What to put in front of an exported function.
+ */
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+# define K_EXPORT               __declspec(dllexport)
+#else
+# define K_EXPORT
+#endif
+
+/** @def K_IMPORT
+ * What to put in front of an imported function.
+ */
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+# define K_IMPORT               __declspec(dllimport)
+#else
+# define K_IMPORT               extern
+#endif
+
+/** @def K_DECL_EXPORT
+ * Declare an exported function.
+ * @param type      The return type.
+ */
+#define K_DECL_EXPORT(type)     K_EXPORT type
+
+/** @def K_DECL_IMPORT
+ * Declare an import function.
+ * @param type      The return type.
+ */
+#define K_DECL_IMPORT(type)     K_IMPORT type
+
+/** @def K_DECL_INLINE
+ * Declare an inline function.
+ * @param type      The return type.
+ * @remark  Don't use on (class) methods.
+ */
+#define K_DECL_INLINE(type)     K_INLINE type
+
+
+/** Get the minimum of two values. */
+#define K_MIN(a, b)             ( (a) <= (b) ? (a) : (b) )
+/** Get the maximum of two values. */
+#define K_MAX(a, b)             ( (a) >= (b) ? (a) : (b) )
+/** Calculate the offset of a structure member. */
+#define K_OFFSETOF(strct, memb) ( (KSIZE)( &((strct *)0)->memb ) )
+/** Align a size_t value. */
+#define K_ALIGN_Z(val, align)   ( ((val) + ((align) - 1)) & ~(KSIZE)((align) - 1) )
+/** Align a void * value. */
+#define K_ALIGN_P(pv, align)    ( (void *)( ((KUPTR)(pv) + ((align) - 1)) & ~(KUPTR)((align) - 1) ) )
+/** Number of elements in an array. */
+#define K_ELEMENTS(a)           ( sizeof(a) / sizeof((a)[0]) )
+/** Checks if the specified pointer is a valid address or not. */
+#define K_VALID_PTR(ptr)        ( (KUPTR)(ptr) + 0x1000U >= 0x2000U )
+/** Makes a 32-bit bit mask. */
+#define K_BIT32(bit)            ( KU32_C(1) << (bit))
+/** Makes a 64-bit bit mask. */
+#define K_BIT64(bit)            ( KU64_C(1) << (bit))
+/** Shuts up unused parameter and unused variable warnings. */
+#define K_NOREF(var)            ( (void)(var) )
+
+
+/** @name Parameter validation macros
+ * @{ */
+
+/** Return/Crash validation of a string argument. */
+#define K_VALIDATE_STRING(str) \
+    do { \
+        if (!K_VALID_PTR(str)) \
+            return KERR_INVALID_POINTER; \
+        kHlpStrLen(str); \
+    } while (0)
+
+/** Return/Crash validation of an optional string argument. */
+#define K_VALIDATE_OPTIONAL_STRING(str) \
+    do { \
+        if (str) \
+            K_VALIDATE_STRING(str); \
+    } while (0)
+
+/** Return/Crash validation of an output buffer. */
+#define K_VALIDATE_BUFFER(buf, cb) \
+    do { \
+        if (!K_VALID_PTR(buf)) \
+            return KERR_INVALID_POINTER; \
+        if ((cb) != 0) \
+        { \
+            KU8             __b; \
+            KU8 volatile   *__pb = (KU8 volatile *)(buf); \
+            KSIZE           __cbPage1 = 0x1000 - ((KUPTR)(__pb) & 0xfff); /* ASSUMES page size! */ \
+            __b = *__pb; *__pb = 0xff; *__pb = __b; \
+            if ((cb) > __cbPage1) \
+            { \
+                KSIZE __cb = (cb) - __cbPage1; \
+                __pb -= __cbPage1; \
+                for (;;) \
+                { \
+                    __b = *__pb; *__pb = 0xff; *__pb = __b; \
+                    if (__cb < 0x1000) \
+                        break; \
+                    __pb += 0x1000; \
+                    __cb -= 0x1000; \
+                } \
+            } \
+        } \
+        else \
+            return KERR_INVALID_PARAMETER; \
+    } while (0)
+
+/** Return/Crash validation of an optional output buffer. */
+#define K_VALIDATE_OPTIONAL_BUFFER(buf, cb) \
+    do { \
+        if ((buf) && (cb) != 0) \
+            K_VALIDATE_BUFFER(buf, cb); \
+    } while (0)
+
+/** Return validation of an enum argument. */
+#define K_VALIDATE_ENUM(arg, enumname) \
+    do { \
+        if ((arg) <= enumname##_INVALID || (arg) >= enumname##_END) \
+            return KERR_INVALID_PARAMETER; \
+    } while (0)
+
+/** Return validation of a flags argument. */
+#define K_VALIDATE_FLAGS(arg, AllowedMask) \
+    do { \
+        if ((arg) & ~(AllowedMask)) \
+            return KERR_INVALID_PARAMETER; \
+    } while (0)
+
+/** @} */
+
+/** @def NULL
+ * The nil pointer value. */
+#ifndef NULL
+# ifdef __cplusplus
+#  define NULL          0
+# else
+#  define NULL          ((void *)0)
+# endif
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kErr.h
===================================================================
--- /trunk/include/k/kErr.h	(revision 2)
+++ /trunk/include/k/kErr.h	(revision 2)
@@ -0,0 +1,64 @@
+/* $Id$ */
+/** @file
+ * kErr - Status Code API.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___k_kErr_h___
+#define ___k_kErr_h___
+
+/** @defgroup   grp_kErr        kErr - Status Code API
+ * @{
+ */
+
+/** @def KERR_DECL
+ * Declares a kRdr function according to build context.
+ * @param type          The return type.
+ */
+#if defined(KERR_BUILDING_DYNAMIC)
+# define KERR_DECL(type)    K_DECL_EXPORT(type)
+#elif defined(KRDR_BUILT_DYNAMIC)
+# define KERR_DECL(type)    K_DECL_IMPORT(type)
+#else
+# define KERR_DECL(type)    type
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KERR_DECL(const char *) kErrName(int rc);
+KERR_DECL(int)  kErrFromErrno(int);
+KERR_DECL(int)  kErrFromOS2(unsigned long rcOs2);
+KERR_DECL(int)  kErrFromNtStatus(long rcNtStatus);
+KERR_DECL(int)  kErrFromMach(int rcMach);
+KERR_DECL(int)  kErrFromDarwin(int rcDarwin);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kErrors.h
===================================================================
--- /trunk/include/k/kErrors.h	(revision 2)
+++ /trunk/include/k/kErrors.h	(revision 2)
@@ -0,0 +1,307 @@
+/* $Id$ */
+/** @file
+ * kErrors - Status Codes.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___k_kErrors_h___
+#define ___k_kErrors_h___
+
+/** @defgroup grp_kErrors   Status Codes.
+ * @{
+ */
+/** The base of the kErrors status codes. */
+#define KERR_BASE                                       42000
+
+/** @name General
+ * @{
+ */
+/** The base of the general status codes. */
+#define KERR_GENERAL_BASE                               (KERR_BASE)
+/** Generic error. */
+#define KERR_GENERAL_FAILURE                            (KERR_GENERAL_BASE + 1)
+/** Out of memory. */
+#define KERR_NO_MEMORY                                  (KERR_GENERAL_BASE + 2)
+/** Hit some unimplemented functionality - feel free to implement it :-) . */
+#define KERR_NOT_IMPLEMENTED                            (KERR_GENERAL_BASE + 3)
+/** An environment variable wasn't found. */
+#define KERR_ENVVAR_NOT_FOUND                           (KERR_GENERAL_BASE + 4)
+/** Buffer overflow. */
+#define KERR_BUFFER_OVERFLOW                            (KERR_GENERAL_BASE + 5)
+/** @}*/
+
+/** @name Input Validation
+ * @{
+ */
+/** The base of the input validation status codes. */
+#define KERR_INPUT_BASE                                 (KERR_GENERAL_BASE + 6)
+/** An API was given an invalid parameter. */
+#define KERR_INVALID_PARAMETER                          (KERR_INPUT_BASE + 0)
+/** A pointer argument is not valid. */
+#define KERR_INVALID_POINTER                            (KERR_INPUT_BASE + 1)
+/** A handle argument is not valid. */
+#define KERR_INVALID_HANDLE                             (KERR_INPUT_BASE + 2)
+/** An offset argument is not valid. */
+#define KERR_INVALID_OFFSET                             (KERR_INPUT_BASE + 3)
+/** A size argument is not valid. */
+#define KERR_INVALID_SIZE                               (KERR_INPUT_BASE + 4)
+/** A range argument is not valid. */
+#define KERR_INVALID_RANGE                              (KERR_INPUT_BASE + 5)
+/** A parameter is out of range. */
+#define KERR_OUT_OF_RANGE                               (KERR_INPUT_BASE + 6)
+/** @} */
+
+/** @name File System and I/O
+ * @{
+ */
+/** The base of the file system and I/O status cdoes. */
+#define KERR_FILE_SYSTEM_AND_IO_BASE                    (KERR_INPUT_BASE + 7)
+/** The specified file was not found. */
+#define KERR_FILE_NOT_FOUND                             (KERR_FILE_SYSTEM_AND_IO_BASE + 0)
+/** End of file. */
+#define KERR_EOF                                        (KERR_FILE_SYSTEM_AND_IO_BASE + 1)
+/** @} */
+
+/** @name   kDbg Specific
+ * @{
+ */
+/** The base of the kDbg specific status codes. */
+#define KDBG_ERR_BASE                                   (KERR_FILE_SYSTEM_AND_IO_BASE + 2)
+/** The (module) format isn't known to use. */
+#define KDBG_ERR_UNKOWN_FORMAT                          (KDBG_ERR_BASE + 0)
+/** The (module) format isn't supported by this kDbg build. */
+#define KDBG_ERR_FORMAT_NOT_SUPPORTED                   (KDBG_ERR_BASE + 1)
+/** The (module) format isn't supported by this kDbg build. */
+#define KDBG_ERR_BAD_EXE_FORMAT                         (KDBG_ERR_BASE + 2)
+/** A specified address or an address found in the debug info is invalid. */
+#define KDBG_ERR_INVALID_ADDRESS                        (KDBG_ERR_BASE + 3)
+/** The dbghelp.dll is too old or something like that. */
+#define KDBG_ERR_DBGHLP_VERSION_MISMATCH                (KDBG_ERR_BASE + 4)
+/** @} */
+
+/** @name   kRdr Specific
+ * @{
+ */
+/** the base of the kRdr specific status codes. */
+#define KRDR_ERR_BASE                                   (KDBG_ERR_BASE + 5)
+/** The file reader can't take more concurrent mappings. */
+#define KRDR_ERR_TOO_MANY_MAPPINGS                      (KRDR_ERR_BASE + 0)
+/** The pRdr instance passed to a kRdrBuf* API isn't a buffered instance. */
+#define KRDR_ERR_NOT_BUFFERED_RDR                       (KRDR_ERR_BASE + 1)
+/** The line is too long to fit in the buffer passed to kRdrBufLine or kRdrBufLineEx. */
+#define KRDR_ERR_LINE_TOO_LONG                          (KRDR_ERR_BASE + 2)
+/** @} */
+
+/** @name   kLdr Specific
+ * @{
+ */
+/** The base of the kLdr specific status codes. */
+#define KLDR_ERR_BASE                                   (KRDR_ERR_BASE + 3)
+
+/** The image format is unknown. */
+#define KLDR_ERR_UNKNOWN_FORMAT                         (KLDR_ERR_BASE + 0)
+/** The MZ image format isn't supported by this kLdr build. */
+#define KLDR_ERR_MZ_NOT_SUPPORTED                       (KLDR_ERR_BASE + 1)
+/** The NE image format isn't supported by this kLdr build. */
+#define KLDR_ERR_NE_NOT_SUPPORTED                       (KLDR_ERR_BASE + 2)
+/** The LX image format isn't supported by this kLdr build. */
+#define KLDR_ERR_LX_NOT_SUPPORTED                       (KLDR_ERR_BASE + 3)
+/** The LE image format isn't supported by this kLdr build. */
+#define KLDR_ERR_LE_NOT_SUPPORTED                       (KLDR_ERR_BASE + 4)
+/** The PE image format isn't supported by this kLdr build. */
+#define KLDR_ERR_PE_NOT_SUPPORTED                       (KLDR_ERR_BASE + 5)
+/** The ELF image format isn't supported by this kLdr build. */
+#define KLDR_ERR_ELF_NOT_SUPPORTED                      (KLDR_ERR_BASE + 6)
+/** The mach-o image format isn't supported by this kLdr build. */
+#define KLDR_ERR_MACHO_NOT_SUPPORTED                    (KLDR_ERR_BASE + 7)
+/** The FAT image format isn't supported by this kLdr build or
+ * a direct open was attempt without going thru the FAT file provider.
+ * FAT images are also known as Universal Binaries. */
+#define KLDR_ERR_FAT_NOT_SUPPORTED                      (KLDR_ERR_BASE + 8)
+/** The a.out image format isn't supported by this kLdr build. */
+#define KLDR_ERR_AOUT_NOT_SUPPORTED                     (KLDR_ERR_BASE + 9)
+
+/** The module wasn't loaded dynamically. */
+#define KLDR_ERR_NOT_LOADED_DYNAMICALLY                 (KLDR_ERR_BASE + 10)
+/** The module wasn't found. */
+#define KLDR_ERR_MODULE_NOT_FOUND                       (KLDR_ERR_BASE + 11)
+/** A prerequisit module wasn't found. */
+#define KLDR_ERR_PREREQUISITE_MODULE_NOT_FOUND          (KLDR_ERR_BASE + 12)
+/** The module is being terminated and can therefore not be loaded. */
+#define KLDR_ERR_MODULE_TERMINATING                     (KLDR_ERR_BASE + 13)
+/** A prerequisit module is being terminated and can therefore not be loaded. */
+#define KLDR_ERR_PREREQUISITE_MODULE_TERMINATING        (KLDR_ERR_BASE + 14)
+/** The module initialization failed. */
+#define KLDR_ERR_MODULE_INIT_FAILED                     (KLDR_ERR_BASE + 15)
+/** The initialization of a prerequisite module failed. */
+#define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED        (KLDR_ERR_BASE + 16)
+/** The module has already failed initialization and can't be attempted reloaded until
+ * after we've finished garbage collection. */
+#define KLDR_ERR_MODULE_INIT_FAILED_ALREADY             (KLDR_ERR_BASE + 17)
+/** A prerequisite module has already failed initialization and can't be attempted
+ * reloaded until after we've finished garbage collection. */
+#define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY (KLDR_ERR_BASE + 18)
+/** Prerequisite recursed too deeply. */
+#define KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY       (KLDR_ERR_BASE + 19)
+/** Failed to allocate the main stack. */
+#define KLDR_ERR_MAIN_STACK_ALLOC_FAILED                (KLDR_ERR_BASE + 20)
+/** Symbol not found. */
+#define KLDR_ERR_SYMBOL_NOT_FOUND                       (KLDR_ERR_BASE + 21)
+/** A forward symbol was encountered but the caller didn't provide any means to resolve it. */
+#define KLDR_ERR_FORWARDER_SYMBOL                       (KLDR_ERR_BASE + 22)
+/** Encountered a bad fixup. */
+#define KLDR_ERR_BAD_FIXUP                              (KLDR_ERR_BASE + 23)
+/** The import ordinal was out of bounds. */
+#define KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS           (KLDR_ERR_BASE + 24)
+/** A forwarder chain was too long. */
+#define KLDR_ERR_TOO_LONG_FORWARDER_CHAIN               (KLDR_ERR_BASE + 25)
+/** The module has no debug info. */
+#define KLDR_ERR_NO_DEBUG_INFO                          (KLDR_ERR_BASE + 26)
+/** The module is already mapped.
+ * kLdrModMap() can only be called once (without kLdrModUnmap() in between). */
+#define KLDR_ERR_ALREADY_MAPPED                         (KLDR_ERR_BASE + 27)
+/** The module was not mapped.
+ * kLdrModUnmap() should not called without being preceeded by a kLdrModMap(). */
+#define KLDR_ERR_NOT_MAPPED                             (KLDR_ERR_BASE + 28)
+/** Couldn't fit the address value into the field. Typically a relocation kind of error. */
+#define KLDR_ERR_ADDRESS_OVERFLOW                       (KLDR_ERR_BASE + 29)
+/** Couldn't fit a calculated size value into the native size type of the host. */
+#define KLDR_ERR_SIZE_OVERFLOW                          (KLDR_ERR_BASE + 30)
+/** Thread attach failed. */
+#define KLDR_ERR_THREAD_ATTACH_FAILED                   (KLDR_ERR_BASE + 31)
+/** The module wasn't a DLL or object file. */
+#define KLDR_ERR_NOT_DLL                                (KLDR_ERR_BASE + 32)
+/** The module wasn't an EXE. */
+#define KLDR_ERR_NOT_EXE                                (KLDR_ERR_BASE + 33)
+/** Not implemented yet. */
+#define KLDR_ERR_TODO                                   (KLDR_ERR_BASE + 34)
+/** @} */
+
+/** @name kLdrModPE Specific
+ * @{
+ */
+/** The base of the kLdrModPE specific status codes. */
+#define KLDR_ERR_PE_BASE                                (KLDR_ERR_BASE + 35)
+/** The machine isn't supported by the interpreter. */
+#define KLDR_ERR_PE_UNSUPPORTED_MACHINE                 (KLDR_ERR_PE_BASE + 0)
+/** The file handler isn't valid. */
+#define KLDR_ERR_PE_BAD_FILE_HEADER                     (KLDR_ERR_PE_BASE + 1)
+/** The the optional headers isn't valid. */
+#define KLDR_ERR_PE_BAD_OPTIONAL_HEADER                 (KLDR_ERR_PE_BASE + 2)
+/** One of the section headers aren't valid. */
+#define KLDR_ERR_PE_BAD_SECTION_HEADER                  (KLDR_ERR_PE_BASE + 3)
+/** Bad forwarder entry. */
+#define KLDR_ERR_PE_BAD_FORWARDER                       (KLDR_ERR_PE_BASE + 4)
+/** Forwarder module not found in the import descriptor table. */
+#define KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND          (KLDR_ERR_PE_BASE + 5)
+/** Bad PE fixups. */
+#define KLDR_ERR_PE_BAD_FIXUP                           (KLDR_ERR_PE_BASE + 6)
+/** Bad PE import (thunk). */
+#define KLDR_ERR_PE_BAD_IMPORT                          (KLDR_ERR_PE_BASE + 7)
+/** @} */
+
+/** @name kLdrModLX Specific
+ * @{
+ */
+/** The base of the kLdrModLX specific status codes. */
+#define KLDR_ERR_LX_BASE                                (KLDR_ERR_PE_BASE + 8)
+/** validation of LX header failed. */
+#define KLDR_ERR_LX_BAD_HEADER                          (KLDR_ERR_LX_BASE + 0)
+/** validation of the loader section (in the LX header) failed. */
+#define KLDR_ERR_LX_BAD_LOADER_SECTION                  (KLDR_ERR_LX_BASE + 1)
+/** validation of the fixup section (in the LX header) failed. */
+#define KLDR_ERR_LX_BAD_FIXUP_SECTION                   (KLDR_ERR_LX_BASE + 2)
+/** validation of the LX object table failed. */
+#define KLDR_ERR_LX_BAD_OBJECT_TABLE                    (KLDR_ERR_LX_BASE + 3)
+/** A bad page map entry was encountered. */
+#define KLDR_ERR_LX_BAD_PAGE_MAP                        (KLDR_ERR_LX_BASE + 4)
+/** Bad iterdata (EXEPACK) data. */
+#define KLDR_ERR_LX_BAD_ITERDATA                        (KLDR_ERR_LX_BASE + 5)
+/** Bad iterdata2 (EXEPACK2) data. */
+#define KLDR_ERR_LX_BAD_ITERDATA2                       (KLDR_ERR_LX_BASE + 6)
+/** Bad bundle data. */
+#define KLDR_ERR_LX_BAD_BUNDLE                          (KLDR_ERR_LX_BASE + 7)
+/** No soname. */
+#define KLDR_ERR_LX_NO_SONAME                           (KLDR_ERR_LX_BASE + 8)
+/** Bad soname. */
+#define KLDR_ERR_LX_BAD_SONAME                          (KLDR_ERR_LX_BASE + 9)
+/** Bad forwarder entry. */
+#define KLDR_ERR_LX_BAD_FORWARDER                       (KLDR_ERR_LX_BASE + 10)
+/** internal fixup chain isn't implemented yet. */
+#define KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED              (KLDR_ERR_LX_BASE + 11)
+/** @} */
+
+/** @name kLdrModMachO Specific
+ * @{
+ */
+/** The base of the kLdrModMachO specific status codes. */
+#define KLDR_ERR_MACHO_BASE                             (KLDR_ERR_LX_BASE + 12)
+/** Only native endian Mach-O files are supported. */
+#define KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED       (KLDR_ERR_MACHO_BASE + 0)
+/** 64-bit Mach-O files aren't supported yet. */
+#define KLDR_ERR_MACHO_64BIT_NOT_SUPPORTED              (KLDR_ERR_MACHO_BASE + 1)
+/** The Mach-O header is bad or contains new and unsupported features. */
+#define KLDR_ERR_MACHO_BAD_HEADER                       (KLDR_ERR_MACHO_BASE + 2)
+/** The file type isn't supported. */
+#define KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE            (KLDR_ERR_MACHO_BASE + 3)
+/** The machine (cputype / cpusubtype combination) isn't supported. */
+#define KLDR_ERR_MACHO_UNSUPPORTED_MACHINE              (KLDR_ERR_MACHO_BASE + 4)
+/** Bad load command(s). */
+#define KLDR_ERR_MACHO_BAD_LOAD_COMMAND                 (KLDR_ERR_MACHO_BASE + 5)
+/** Encountered an unknown load command.*/
+#define KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND             (KLDR_ERR_MACHO_BASE + 6)
+/** Encountered a load command that's not implemented.*/
+#define KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND         (KLDR_ERR_MACHO_BASE + 7)
+/** Bad section. */
+#define KLDR_ERR_MACHO_BAD_SECTION                      (KLDR_ERR_MACHO_BASE + 8)
+/** Encountered a section type that's not implemented.*/
+#define KLDR_ERR_MACHO_UNSUPPORTED_SECTION              (KLDR_ERR_MACHO_BASE + 9)
+/** Encountered a section type that's not known to the loader. (probably invalid) */
+#define KLDR_ERR_MACHO_UNKNOWN_SECTION                  (KLDR_ERR_MACHO_BASE + 10)
+/** The sections aren't ordered by segment as expected by the loader. */
+#define KLDR_ERR_MACHO_BAD_SECTION_ORDER                (KLDR_ERR_MACHO_BASE + 11)
+/** The image is 32-bit and contains 64-bit load commands or vise versa. */
+#define KLDR_ERR_MACHO_BIT_MIX                          (KLDR_ERR_MACHO_BASE + 12)
+/** Bad MH_OBJECT file. */
+#define KLDR_ERR_MACHO_BAD_OBJECT_FILE                  (KLDR_ERR_MACHO_BASE + 13)
+/** Bad symbol table entry. */
+#define KLDR_ERR_MACHO_BAD_SYMBOL                       (KLDR_ERR_MACHO_BASE + 14)
+/** Unsupported fixup type. */
+#define KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE           (KLDR_ERR_MACHO_BASE + 15)
+/** @} */
+
+/** @name kCpu Specific
+ * @{
+ */
+/** The base of the kCpu specific status codes. */
+#define KCPU_ERR_BASE                                   (KLDR_ERR_MACHO_BASE + 16)
+/** The specified ARCH+CPU pairs aren't compatible. */
+#define KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE                (KCPU_ERR_BASE + 0)
+/** @} */
+
+/** End of the valid status codes. */
+#define KERR_END                                        (KCPU_ERR_BASE + 1)
+/** @}*/
+
+#endif
+
Index: /trunk/include/k/kHlp.h
===================================================================
--- /trunk/include/k/kHlp.h	(revision 2)
+++ /trunk/include/k/kHlp.h	(revision 2)
@@ -0,0 +1,49 @@
+/* $Id$ */
+/** @file
+ * kHlp - Helpers, All Of Them.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlp_h___
+#define ___k_kHlp_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kErrors.h>
+#include <k/kHlpAlloc.h>
+#include <k/kHlpAssert.h>
+#include <k/kHlpEnv.h>
+#include <k/kHlpPath.h>
+#include <k/kHlpProcess.h>
+#include <k/kHlpSem.h>
+#include <k/kHlpString.h>
+#include <k/kHlpThread.h>
+
+/** @defgroup grp_kHlp  kHlp - Helper Functions
+ * @{ */
+
+/** @} */
+
+#endif
+
+
Index: /trunk/include/k/kHlpAlloc.h
===================================================================
--- /trunk/include/k/kHlpAlloc.h	(revision 2)
+++ /trunk/include/k/kHlpAlloc.h	(revision 2)
@@ -0,0 +1,74 @@
+/* $Id$ */
+/** @file
+ * kHlpAlloc - Memory Allocation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpAlloc_h___
+#define ___k_kHlpAlloc_h___
+
+#include <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @defgroup grp_kHlpAlloc kHlpAlloc - Memory Allocation
+ * @addtogroup grp_kHlp
+ * @{*/
+
+/** @def kHlpAllocA
+ * The alloca() wrapper. */
+#ifdef __GNUC__
+# define kHlpAllocA(a)      __builtin_alloca(a)
+#elif defined(_MSC_VER)
+# include <malloc.h>
+# define kHlpAllocA(a)      alloca(a)
+#else
+# error "Port Me."
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KHLP_DECL(void *)   kHlpAlloc(KSIZE cb);
+KHLP_DECL(void *)   kHlpAllocZ(KSIZE cb);
+KHLP_DECL(void *)   kHlpDup(const void *pv, KSIZE cb);
+KHLP_DECL(char *)   kHlpStrDup(const char *psz);
+KHLP_DECL(void *)   kHlpRealloc(void *pv, KSIZE cb);
+KHLP_DECL(void)     kHlpFree(void *pv);
+
+KHLP_DECL(int)      kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed);
+KHLP_DECL(int)      kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt);
+KHLP_DECL(int)      kHlpPageFree(void *pv, KSIZE cb);
+
+KHLP_DECL(int)      kHlpHeapInit(void);
+KHLP_DECL(void)     kHlpHeapTerm(void);
+KHLP_DECL(void)     kHlpHeapDonate(void *pv, KSIZE cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kHlpAssert.h
===================================================================
--- /trunk/include/k/kHlpAssert.h	(revision 2)
+++ /trunk/include/k/kHlpAssert.h	(revision 2)
@@ -0,0 +1,169 @@
+/* $Id$ */
+/** @file
+ * kHlpAssert - Assertion Macros.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___kHlpAssert_h___
+#define ___kHlpAssert_h___
+
+#include <k/kHlpDefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup   grp_kHlpAssert - Assertion Macros
+ * @addtogroup grp_kHlp
+ * @{ */
+
+/** @def K_STRICT
+ * Assertions are enabled when K_STRICT is \#defined. */
+
+/** @def kHlpAssertBreakpoint
+ * Emits a breakpoint instruction or somehow triggers a debugger breakpoint.
+ */
+#ifdef _MSC_VER
+# define kHlpAssertBreakpoint() do { __debugbreak(); } while (0)
+#elif defined(__GNUC__)
+# define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0)
+#else
+# error "Port Me"
+#endif
+
+#ifdef K_STRICT
+
+# define kHlpAssert(expr) \
+    do { \
+        if (!(expr)) \
+        { \
+            kHlpAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kHlpAssertBreakpoint(); \
+        }
+    } while (0)
+
+# define kHlpAssertReturn(expr, rcRet) \
+    do { \
+        if (!(expr)) \
+        { \
+            kHlpAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kHlpAssertBreakpoint(); \
+            return (rcRet); \
+        }
+    } while (0)
+
+# define kHlpAssertReturnVoid(expr) \
+    do { \
+        if (!(expr)) \
+        { \
+            kHlpAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kHlpAssertBreakpoint(); \
+            return; \
+        }
+    } while (0)
+
+# define kHlpAssertMsg(expr, msg) \
+    do { \
+        if (!(expr)) \
+        { \
+            kHlpAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kHlpAssertMsg2 msg; \
+            kHlpAssertBreakpoint(); \
+        }
+    } while (0)
+
+# define kHlpAssertMsgReturn(expr, msg, rcRet) \
+    do { \
+        if (!(expr)) \
+        { \
+            kHlpAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kHlpAssertMsg2 msg; \
+            kHlpAssertBreakpoint(); \
+            return (rcRet); \
+        }
+    } while (0)
+
+# define kHlpAssertMsgReturnVoid(expr, msg) \
+    do { \
+        if (!(expr)) \
+        { \
+            kHlpAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kHlpAssertMsg2 msg; \
+            kHlpAssertBreakpoint(); \
+            return; \
+        }
+    } while (0)
+
+#else   /* !K_STRICT */
+# define kHlpAssert(expr)                       do { } while (0)
+# define kHlpAssertReturn(expr, rcRet)          do { if (!(expr)) return (rcRet); } while (0)
+# define kHlpAssertReturnVoid(expr)             do { if (!(expr)) return; } while (0)
+# define kHlpAssertMsg(expr, msg)               do { } while (0)
+# define kHlpAssertMsgReturn(expr, msg, rcRet)  do { if (!(expr)) return (rcRet); } while (0)
+# define kHlpAssertMsgReturnVoid(expr, msg)     do { if (!(expr)) return; } while (0)
+#endif  /* !K_STRICT */
+
+#define kHlpAssertPtr(ptr)                      kHlpAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kHlpAssertPtrReturn(ptr, rcRet)         kHlpAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kHlpAssertPtrReturnVoid(ptr)            kHlpAssertMsgReturnVoid(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)))
+#define kHlpAssertPtrNull(ptr)                  kHlpAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kHlpAssertPtrNullReturn(ptr, rcRet)     kHlpAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kHlpAssertPtrNullReturnVoid(ptr)        kHlpAssertMsgReturnVoid(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)))
+#define kHlpAssertRC(rc)                        kHlpAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc)))
+#define kHlpAssertRCReturn(rc, rcRet)           kHlpAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet))
+#define kHlpAssertRCReturnVoid(rc)              kHlpAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)))
+#define kHlpAssertFailed()                      kHlpAssert(0)
+#define kHlpAssertFailedReturn(rcRet)           kHlpAssertReturn(0, (rcRet))
+#define kHlpAssertFailedReturnVoid()            kHlpAssertReturnVoid(0)
+#define kHlpAssertMsgFailed(msg)                kHlpAssertMsg(0, msg)
+#define kHlpAssertMsgFailedReturn(msg, rcRet)   kHlpAssertMsgReturn(0, msg, (rcRet))
+#define kHlpAssertMsgFailedReturnVoid(msg)      kHlpAssertMsgReturnVoid(0, msg))
+
+/**
+ * Helper function that displays the first part of the assertion message.
+ *
+ * @param   pszExpr         The expression.
+ * @param   pszFile         The file name.
+ * @param   iLine           The line number is the file.
+ * @param   pszFunction     The function name.
+ * @internal
+ */
+KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction);
+
+/**
+ * Helper function that displays custom assert message.
+ *
+ * @param   pszFormat       Format string that get passed to vprintf.
+ * @param   ...             Format arguments.
+ * @internal
+ */
+KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...);
+
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /trunk/include/k/kHlpDefs.h
===================================================================
--- /trunk/include/k/kHlpDefs.h	(revision 2)
+++ /trunk/include/k/kHlpDefs.h	(revision 2)
@@ -0,0 +1,51 @@
+/* $Id$ */
+/** @file
+ * kHlpDefs - Helper Definitions.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpDefs_h___
+#define ___k_kHlpDefs_h___
+
+#include <k/kDefs.h>
+
+/** @defgroup grp_kHlpDefs - Definitions
+ * @addtogroup grp_kHlp
+ * @{ */
+
+/** @def KHLP_DECL
+ * Declares a kHlp function according to build context.
+ * @param type          The return type.
+ */
+#if defined(KHLP_BUILDING_DYNAMIC)
+# define KHLP_DECL(type)    K_DECL_EXPORT(type)
+#elif defined(KHLP_BUILT_DYNAMIC)
+# define KHLP_DECL(type)    K_DECL_IMPORT(type)
+#else
+# define KHLP_DECL(type)    type
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kHlpEnv.h
===================================================================
--- /trunk/include/k/kHlpEnv.h	(revision 2)
+++ /trunk/include/k/kHlpEnv.h	(revision 2)
@@ -0,0 +1,51 @@
+/* $Id$ */
+/** @file
+ * kHlpEnv - Environment Manipulation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpEnv_h___
+#define ___k_kHlpEnv_h___
+
+#include <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @defgroup grp_kHlpEnv kHlpEnv - Environment Manipulation
+ * @addtogroup grp_kHlp
+ * @{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KHLP_DECL(int)  kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal);
+KHLP_DECL(int)  kHlpGetEnvUZ(const char *pszVar, KSIZE *pcb);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kHlpPath.h
===================================================================
--- /trunk/include/k/kHlpPath.h	(revision 2)
+++ /trunk/include/k/kHlpPath.h	(revision 2)
@@ -0,0 +1,53 @@
+/* $Id$ */
+/** @file
+ * kHlpPath - Path Manipulation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpPath_h___
+#define ___k_kHlpPath_h___
+
+#include <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @defgroup grp_kHlpPath kHlpPath - Path Manipulation
+ * @addtogroup grp_kHlp
+ * @{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KHLP_DECL(char *)  kHlpGetFilename(const char *pszFilename);
+KHLP_DECL(char *)  kHlpGetSuff(const char *pszFilename);
+KHLP_DECL(char *)  kHlpGetExt(const char *pszFilename);
+KHLP_DECL(int)     kHlpIsFilenameOnly(const char *pszFilename);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kHlpProcess.h
===================================================================
--- /trunk/include/k/kHlpProcess.h	(revision 2)
+++ /trunk/include/k/kHlpProcess.h	(revision 2)
@@ -0,0 +1,50 @@
+/* $Id$ */
+/** @file
+ * kHlpProcess - Process Management.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpProcess_h___
+#define ___k_kHlpProcess_h___
+
+#include <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @defgroup grp_kHlpProcess   kHlpProcess - Process Management
+ * @addtogroup grp_kHlp
+ * @{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KHLP_DECL(void) kHlpExit(int rc);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kHlpSem.h
===================================================================
--- /trunk/include/k/kHlpSem.h	(revision 2)
+++ /trunk/include/k/kHlpSem.h	(revision 2)
@@ -0,0 +1,50 @@
+/* $Id$ */
+/** @file
+ * kHlpSem - Semaphores.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpSem_h___
+#define ___k_kHlpSem_h___
+
+#include <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @defgroup grp_kHlpSem kHlpSem - Semaphore
+ * @addtogroup grp_kHlp
+ * @{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
+
Index: /trunk/include/k/kHlpString.h
===================================================================
--- /trunk/include/k/kHlpString.h	(revision 2)
+++ /trunk/include/k/kHlpString.h	(revision 2)
@@ -0,0 +1,152 @@
+/* $Id$ */
+/** @file
+ * kHlpString - String And Memory Routines.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpString_h___
+#define ___k_kHlpString_h___
+
+#include <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+#if 0 /* optimize / fix this later */
+#ifdef __GNUC__
+/** memchr */
+# define kHlpMemChr(a,b,c)      __builtin_memchr(a,b,c)
+/** memcmp */
+# define kHlpMemComp(a,b,c)     __builtin_memcmp(a,b,c)
+/** memcpy */
+# define kHlpMemCopy(a,b,c)     __builtin_memcpy(a,b,c)
+/** memset */
+# define kHlpMemSet(a,b,c)      __builtin_memset(a,b,c)
+/** strchr */
+# define kHlpStrChr(a, b)       __builtin_strchr(a, b)
+/** strcmp */
+# define kHlpStrComp(a, b)      __builtin_strcmp(a, b)
+/** strncmp */
+# define kHlpStrNComp(a,b,c)    __builtin_strncmp(a, b, c)
+/** strlen */
+# define kHlpStrLen(a)          __builtin_strlen(a)
+
+#elif defined(_MSC_VER)
+# pragma intrinsic(memcmp, memcpy, memset, strcmp, strlen)
+/** memcmp */
+# define kHlpMemComp(a,b,c)     memcmp(a,b,c)
+/** memcpy */
+# define kHlpMemCopy(a,b,c)     memcpy(a,b,c)
+/** memset */
+# define kHlpMemSet(a,b,c)      memset(a,b,c)
+/** strcmp */
+# define kHlpStrComp(a, b)      strcmp(a, b)
+/** strlen */
+# define kHlpStrLen(a)          strlen(a)
+#else
+# error "Port Me"
+#endif
+#endif /* disabled */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef kHlpMemChr
+KHLP_DECL(void *)   kHlpMemChr(const void *pv, int ch, KSIZE cb);
+#endif
+#ifndef kHlpMemComp
+KHLP_DECL(int)      kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb);
+#endif
+#ifndef kHlpMemComp
+KHLP_DECL(void *)   kHlpMemPComp(const void *pv1, const void *pv2, KSIZE cb);
+#endif
+#ifndef kHlpMemCopy
+KHLP_DECL(void *)   kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb);
+#endif
+#ifndef kHlpMemPCopy
+KHLP_DECL(void *)   kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb);
+#endif
+#ifndef kHlpMemMove
+KHLP_DECL(void *)   kHlpMemMove(void *pv1, const void *pv2, KSIZE cb);
+#endif
+#ifndef kHlpMemPMove
+KHLP_DECL(void *)   kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb);
+#endif
+#ifndef kHlpMemSet
+KHLP_DECL(void *)   kHlpMemSet(void *pv1, int ch, KSIZE cb);
+#endif
+#ifndef kHlpMemPSet
+KHLP_DECL(void *)   kHlpMemPSet(void *pv1, int ch, KSIZE cb);
+#endif
+KHLP_DECL(int)      kHlpMemICompAscii(const void *pv1, const void *pv2, KSIZE cb);
+
+#ifndef kHlpStrCat
+KHLP_DECL(char *)   kHlpStrCat(char *psz1, const char *psz2);
+#endif
+#ifndef kHlpStrPCat
+KHLP_DECL(char *)   kHlpStrPCat(char *psz1, const char *psz2);
+#endif
+#ifndef kHlpStrNCat
+KHLP_DECL(char *)   kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb);
+#endif
+#ifndef kHlpStrPNCat
+KHLP_DECL(char *)   kHlpStrNPCat(char *psz1, const char *psz2, KSIZE cb);
+#endif
+#ifndef kHlpStrChr
+KHLP_DECL(char *)   kHlpStrChr(const char *psz, int ch);
+#endif
+#ifndef kHlpStrRChr
+KHLP_DECL(char *)   kHlpStrRChr(const char *psz, int ch);
+#endif
+#ifndef kHlpStrComp
+KHLP_DECL(int)      kHlpStrComp(const char *psz1, const char *psz2);
+#endif
+KHLP_DECL(char *)   kHlpStrPComp(const char *psz1, const char *psz2);
+#ifndef kHlpStrNComp
+KHLP_DECL(int)      kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cch);
+#endif
+KHLP_DECL(char *)   kHlpStrNPComp(const char *psz1, const char *psz2, KSIZE cch);
+KHLP_DECL(int)      kHlpStrICompAscii(const char *pv1, const char *pv2);
+KHLP_DECL(char *)   kHlpStrIPCompAscii(const char *pv1, const char *pv2);
+KHLP_DECL(int)      kHlpStrNICompAscii(const char *pv1, const char *pv2, KSIZE cch);
+KHLP_DECL(char *)   kHlpStrNIPCompAscii(const char *pv1, const char *pv2, KSIZE cch);
+#ifndef kHlpStrCopy
+KHLP_DECL(char *)   kHlpStrCopy(char *psz1, const char *psz2);
+#endif
+#ifndef kHlpStrPCopy
+KHLP_DECL(char *)   kHlpStrPCopy(char *psz1, const char *psz2);
+#endif
+#ifndef kHlpStrLen
+KHLP_DECL(KSIZE)    kHlpStrLen(const char *psz1);
+#endif
+#ifndef kHlpStrNLen
+KHLP_DECL(KSIZE)    kHlpStrNLen(const char *psz, KSIZE cchMax);
+#endif
+
+KHLP_DECL(char *)   kHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
Index: /trunk/include/k/kHlpSys.h
===================================================================
--- /trunk/include/k/kHlpSys.h	(revision 2)
+++ /trunk/include/k/kHlpSys.h	(revision 2)
@@ -0,0 +1,75 @@
+/* $Id$ */
+/** @file
+ * kHlpSys - System Call Prototypes.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpSys_h___
+#define ___k_kHlpSys_h___
+
+#include <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @defgroup grp_kHlpSys kHlpSys - System Call Prototypes
+ * @addtogroup grp_kHlp
+ * @{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* common unix stuff. */
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+KSSIZE      kHlpSys_readlink(const char *pszPath, char *pszBuf, KSIZE cbBuf);
+int         kHlpSys_open(const char *filename, int flags, int mode);
+int         kHlpSys_close(int fd);
+KFOFF       kHlpSys_lseek(int fd, int whench, KFOFF off);
+KSSIZE      kHlpSys_read(int fd, void *pvBuf, KSIZE cbBuf);
+KSSIZE      kHlpSys_write(int fd, const void *pvBuf, KSIZE cbBuf);
+void       *kHlpSys_mmap(void *addr, KSIZE len, int prot, int flags, int fd, KI64 off);
+int         kHlpSys_mprotect(void *addr, KSIZE len, int prot);
+int         kHlpSys_munmap(void *addr, KSIZE len);
+void        kHlpSys_exit(int rc);
+#endif
+
+/* specific */
+#if K_OS == K_OS_DARWIN
+
+#elif K_OS == K_OS_LINUX
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
+
Index: /trunk/include/k/kHlpThread.h
===================================================================
--- /trunk/include/k/kHlpThread.h	(revision 2)
+++ /trunk/include/k/kHlpThread.h	(revision 2)
@@ -0,0 +1,51 @@
+/* $Id$ */
+/** @file
+ * kHlpThread - Thread Manipulation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kHlpThread_h___
+#define ___k_kHlpThread_h___
+
+#include <k/kHlpDefs.h>
+#include <k/kTypes.h>
+
+/** @defgroup grp_kHlpThread kHlpThread - Thread Management
+ * @addtogroup grp_kHlp
+ * @{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KHLP_DECL(void)    kHlpSleep(unsigned cMillies);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
+
Index: /trunk/include/k/kLdr.h
===================================================================
--- /trunk/include/k/kLdr.h	(revision 2)
+++ /trunk/include/k/kLdr.h	(revision 2)
@@ -0,0 +1,917 @@
+/* $Id$ */
+/** @file
+ *
+ * kLdr - The Dynamic Loader.
+ *
+ * Copyright (c) 2006 knut st. osmundsen <bird@anduin.net>
+ *
+ *
+ * This file is part of kLdr.
+ *
+ * kLdr is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kLdr 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kLdr; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kLdr_h___
+#define ___k_kLdr_h___
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Include the base typedefs and macros.
+ */
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kCpus.h>
+
+
+/** @defgroup grp_kLdrBasic     kLdr Basic Types
+ * @{ */
+
+/** The kLdr address type. */
+typedef KU64 KLDRADDR;
+/** Pointer to a kLdr address. */
+typedef KLDRADDR *PKLDRADDR;
+/** Pointer to a const kLdr address. */
+typedef const KLDRADDR *PCKLDRADDR;
+
+/** NIL address. */
+#define NIL_KLDRADDR    (~(KU64)0)
+
+/** @def PRI_KLDRADDR
+ * printf format type. */
+#ifdef _MSC_VER
+# define PRI_KLDRADDR    "I64x"
+#else
+# define PRI_KLDRADDR    "llx"
+#endif
+
+/** Align a KSIZE value. */
+#define KLDR_ALIGN_ADDR(val, align) ( ((val) + ((align) - 1)) & ~(KLDRADDR)((align) - 1) )
+
+
+/** The kLdr size type. */
+typedef KU64 KLDRSIZE;
+/** Pointer to a kLdr size. */
+typedef KLDRSIZE *PKLDRSIZE;
+/** Pointer to a const kLdr size. */
+typedef const KLDRSIZE *PCKLDRSIZE;
+
+/** @def PRI_KLDRSIZE
+ * printf format type. */
+#ifdef _MSC_VER
+# define PRI_KLDRSIZE    "I64x"
+#else
+# define PRI_KLDRSIZE    "llx"
+#endif
+
+
+/** The kLdr file offset type. */
+typedef long KLDRFOFF;
+/** Pointer to a kLdr file offset type. */
+typedef KLDRFOFF *PKLDRFOFF;
+/** Pointer to a const kLdr file offset type. */
+typedef const KLDRFOFF *PCKLDRFOFF;
+
+/** @def PRI_KLDRFOFF
+ * printf format type. */
+#define PRI_KLDRFOFF     "lx"
+
+
+/**
+ * Union of all the integer types.
+ */
+typedef union KLDRU
+{
+    KI8             i8;     /**< KI8 view. */
+    KU8             u8;     /**< KU8 view. */
+    KI16            i16;    /**< KI16 view. */
+    KU16            u16;    /**< KU16 view. */
+    KI32            i32;    /**< KI32 view. */
+    KU32            u32;    /**< KU32 view. */
+    KI64            i64;    /**< KI64 view. */
+    KU64            u64;    /**< KU64 view. */
+
+    KI8             ai8[8]; /**< KI8 array view . */
+    KU8             au8[8]; /**< KU8 array view. */
+    KI16            ai16[4];/**< KI16 array view . */
+    KU16            au16[4];/**< KU16 array view. */
+    KI32            ai32[2];/**< KI32 array view . */
+    KU32            au32[2];/**< KU32 array view. */
+
+    signed char     ch;     /**< signed char view. */
+    unsigned char   uch;    /**< unsigned char view. */
+    signed short    s;      /**< signed short view. */
+    unsigned short  us;     /**< unsigned short view. */
+    signed int      i;      /**< signed int view. */
+    unsigned int    u;      /**< unsigned int view. */
+    signed long     l;      /**< signed long view. */
+    unsigned long   ul;     /**< unsigned long view. */
+    void           *pv;     /**< void pointer view. */
+
+    KLDRADDR        Addr;   /**< kLdr address view. */
+    KLDRSIZE        Size;   /**< kLdr size view. */
+} KLDRU;
+/** Pointer to an integer union. */
+typedef KLDRU *PKLDRU;
+/** Pointer to a const integer union. */
+typedef const KLDRU *PCKLDRU;
+
+
+/**
+ * Union of pointers to all the integer types.
+ */
+typedef union KLDRPU
+{
+    KI8            *pi8;    /**< KI8 view. */
+    KU8            *pu8;    /**< KU8 view. */
+    KI16           *pi16;   /**< KI16 view. */
+    KU16           *pu16;   /**< KU16 view. */
+    KI32           *pi32;   /**< KI32 view. */
+    KU32           *pu32;   /**< KU32 view. */
+    KI64           *pi64;   /**< KI64 view. */
+    KU64           *pu64;   /**< KU64 view. */
+
+    signed char    *pch;    /**< signed char view. */
+    unsigned char  *puch;   /**< unsigned char view. */
+    signed short   *ps;     /**< signed short view. */
+    unsigned short *pus;    /**< unsigned short view. */
+    signed int     *pi;     /**< signed int view. */
+    unsigned int   *pu;     /**< unsigned int view. */
+    signed long    *pl;     /**< signed long view. */
+    unsigned long  *pul;    /**< unsigned long view. */
+    void           *pv;     /**< void pointer view. */
+} KLDRPU;
+/** Pointer to an integer pointer union. */
+typedef KLDRPU *PKLDRPU;
+/** Pointer to a const integer pointer union. */
+typedef const KLDRPU *PCKLDRPU;
+
+/** @} */
+
+
+/** @defgroup grp_kLdrMod   kLdrMod - The executable image intepreter
+ * @{ */
+
+/**
+ * Debug info type (from the loader point of view).
+ */
+typedef enum KLDRDBGINFOTYPE
+{
+    /** The usual invalid enum value. */
+    KLDRDBGINFOTYPE_INVALID = 0,
+    /** Unknown debug info format. */
+    KLDRDBGINFOTYPE_UNKNOWN,
+    /** Stabs. */
+    KLDRDBGINFOTYPE_STABS,
+    /** Debug With Arbitrary Record Format (DWARF). */
+    KLDRDBGINFOTYPE_DWARF,
+    /** Microsoft Codeview debug info. */
+    KLDRDBGINFOTYPE_CODEVIEW,
+    /** Watcom debug info. */
+    KLDRDBGINFOTYPE_WATCOM,
+    /** IBM High Level Language debug info.. */
+    KLDRDBGINFOTYPE_HLL,
+    /** The end of the valid debug info values (exclusive). */
+    KLDRDBGINFOTYPE_END,
+    /** Blow the type up to 32-bit. */
+    KLDRDBGINFOTYPE_32BIT_HACK = 0x7fffffff
+} KLDRDBGINFOTYPE;
+/** Pointer to a kLdr debug info type. */
+typedef KLDRDBGINFOTYPE *PKLDRDBGINFOTYPE;
+
+
+/**
+ * Stack information.
+ */
+typedef struct KLDRSTACKINFO
+{
+    /** The base address of the stack (sub) segment.
+     * Set this to NIL_KLDRADDR if the module doesn't include any stack segment. */
+    KLDRADDR        Address;
+    /** The base address of the stack (sub) segment, link address.
+     * Set this to NIL_KLDRADDR if the module doesn't include any stack (sub)segment. */
+    KLDRADDR        LinkAddress;
+    /** The stack size of the main thread.
+     * If no stack (sub)segment in the module, this is the stack size of the main thread.
+     * If the module doesn't contain this kind of information this field will be set to 0. */
+    KLDRSIZE        cbStack;
+    /** The stack size of non-main threads.
+     * If the module doesn't contain this kind of information this field will be set to 0. */
+    KLDRSIZE        cbStackThread;
+} KLDRSTACKINFO;
+/** Pointer to stack information. */
+typedef KLDRSTACKINFO *PKLDRSTACKINFO;
+/** Pointer to const stack information. */
+typedef const KLDRSTACKINFO *PCKLDRSTACKINFO;
+
+
+/**
+ * Loader segment.
+ */
+typedef struct KLDRSEG
+{
+    /** Variable free to use for the kLdr user. */
+    void           *pvUser;
+    /** The segment name. (Might not be zero terminated!) */
+    const char     *pchName;
+    /** The length of the segment name. */
+    KU32            cchName;
+    /** The flat selector to use for the segment (i.e. data/code).
+     * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */
+    KU16            SelFlat;
+    /** The 16-bit selector to use for the segment.
+     * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */
+    KU16            Sel16bit;
+    /** Segment flags. */
+    KU32            fFlags;
+    /** The segment protection. */
+    KPROT        enmProt;
+    /** The size of the segment. */
+    KLDRSIZE        cb;
+    /** The required segment alignment.
+     * The to 0 if the segment isn't supposed to be mapped. */
+    KLDRADDR        Alignment;
+    /** The link address.
+     * Set to NIL_KLDRADDR if the segment isn't supposed to be
+     * mapped or if the image doesn't have link addresses. */
+    KLDRADDR        LinkAddress;
+    /** File offset of the segment.
+     * Set to -1 if no file backing (like BSS). */
+    KLDRFOFF        offFile;
+    /** Size of the file bits of the segment.
+     * Set to -1 if no file backing (like BSS). */
+    KLDRFOFF        cbFile;
+    /** The relative virtual address when mapped.
+     * Set to NIL_KLDRADDR if the segment isn't supposed to be mapped. */
+    KLDRADDR        RVA;
+    /** The size of the segment including the alignment gap up to the next segment when mapped. */
+    KSIZE           cbMapped;
+    /** The address the segment was mapped at by kLdrModMap().
+     * Set to 0 if not mapped. */
+    KUPTR           MapAddress;
+} KLDRSEG;
+
+
+/** @name Segment flags
+ * @{ */
+/** The segment is 16-bit. When not set the default of the target architecture is assumed. */
+#define KLDRSEG_FLAG_16BIT          1
+/** The segment requires a 16-bit selector alias. (OS/2) */
+#define KLDRSEG_FLAG_OS2_ALIAS16    2
+/** Conforming segment (x86 weirdness). (OS/2) */
+#define KLDRSEG_FLAG_OS2_CONFORM    4
+/** IOPL (ring-2) segment. (OS/2) */
+#define KLDRSEG_FLAG_OS2_IOPL       8
+/** @} */
+
+
+/**
+ * Loader module format.
+ */
+typedef enum KLDRFMT
+{
+    /** The usual invalid 0 format. */
+    KLDRFMT_INVALID = 0,
+    /** The native OS loader. */
+    KLDRFMT_NATIVE,
+    /** The AOUT loader. */
+    KLDRFMT_AOUT,
+    /** The ELF loader. */
+    KLDRFMT_ELF,
+    /** The LX loader. */
+    KLDRFMT_LX,
+    /** The Mach-O loader. */
+    KLDRFMT_MACHO,
+    /** The PE loader. */
+    KLDRFMT_PE,
+    /** The end of the valid format values (exclusive). */
+    KLDRFMT_END,
+    /** Hack to blow the type up to 32-bit. */
+    KLDRFMT_32BIT_HACK = 0x7fffffff
+} KLDRFMT;
+
+
+/**
+ * Loader module type.
+ */
+typedef enum KLDRTYPE
+{
+    /** The usual invalid 0 type. */
+    KLDRTYPE_INVALID = 0,
+    /** Object file. */
+    KLDRTYPE_OBJECT,
+    /** Executable module, fixed load address. */
+    KLDRTYPE_EXECUTABLE_FIXED,
+    /** Executable module, relocatable, non-fixed load address. */
+    KLDRTYPE_EXECUTABLE_RELOCATABLE,
+    /** Executable module, position independent code, non-fixed load address. */
+    KLDRTYPE_EXECUTABLE_PIC,
+    /** Shared library, fixed load address.
+     * Typically a system library. */
+    KLDRTYPE_SHARED_LIBRARY_FIXED,
+    /** Shared library, relocatable, non-fixed load address. */
+    KLDRTYPE_SHARED_LIBRARY_RELOCATABLE,
+    /** Shared library, position independent code, non-fixed load address. */
+    KLDRTYPE_SHARED_LIBRARY_PIC,
+    /** DLL that contains no code or data only imports and exports. (Chiefly OS/2.) */
+    KLDRTYPE_FORWARDER_DLL,
+    /** Core or dump. */
+    KLDRTYPE_CORE,
+    /** The end of the valid types values (exclusive). */
+    KLDRTYPE_END,
+    /** Hack to blow the type up to 32-bit. */
+    KLDRTYPE_32BIT_HACK = 0x7fffffff
+} KLDRTYPE;
+
+
+/**
+ * Loader endian indicator.
+ */
+typedef enum KLDRENDIAN
+{
+    /** The usual invalid endian. */
+    KLDRENDIAN_INVALID,
+    /** Little endian. */
+    KLDRENDIAN_LITTLE,
+    /** Bit endian. */
+    KLDRENDIAN_BIG,
+    /** Endianness doesn't have a meaning in the context. */
+    KLDRENDIAN_NA,
+    /** The end of the valid endian values (exclusive). */
+    KLDRENDIAN_END,
+    /** Hack to blow the type up to 32-bit. */
+    KLDRENDIAN_32BIT_HACK = 0x7fffffff
+} KLDRENDIAN;
+
+
+/** Pointer to a module interpreter method table. */
+typedef struct KLDRMODOPS *PKLDRMODOPS;
+/** Pointer to const module interpreter methods table. */
+typedef const struct KLDRMODOPS *PCKLDRMODOPS;
+
+/**
+ * Module interpreter instance.
+ * All members are read only unless you're kLdrMod or the module interpreter.
+ */
+typedef struct KLDRMOD
+{
+    /** Magic number (KLDRMOD_MAGIC). */
+    KU32                u32Magic;
+    /** The format of this module. */
+    KLDRFMT             enmFmt;
+    /** The type of module. */
+    KLDRTYPE            enmType;
+    /** The CPU architecture this module was built for. */
+    KCPUARCH            enmArch;
+    /** The minium cpu this module was built for.
+     * This might not be accurate, so use kLdrModCanExecuteOn() to check. */
+    KCPU                enmCpu;
+    /** The endian used by the module. */
+    KLDRENDIAN          enmEndian;
+    /** The filename length (bytes). */
+    KU32                cchFilename;
+    /** The filename. */
+    const char         *pszFilename;
+    /** The module name. */
+    const char         *pszName;
+    /** The module name length (bytes). */
+    KU32                cchName;
+    /** The number of segments in the module. */
+    KU32                cSegments;
+    /** Pointer to the loader methods.
+     * Not meant for calling directly thru! */
+    PCKLDRMODOPS        pOps;
+    /** Pointer to the read instance. (Can be NULL after kLdrModDone().)*/
+    PKRDR               pRdr;
+    /** The module data. */
+    void               *pvData;
+    /** Segments. (variable size, can be zero) */
+    KLDRSEG             aSegments[1];
+} KLDRMOD, *PKLDRMOD, **PPKLDRMOD;
+
+/** The magic for KLDRMOD::u32Magic. (Kosuke Fujishima) */
+#define KLDRMOD_MAGIC   0x19640707
+
+
+/** Special base address value alias for the link address. */
+#define KLDRMOD_BASEADDRESS_LINK            (~(KLDRADDR)1)
+/** Special base address value alias for the actual load address (must be mapped). */
+#define KLDRMOD_BASEADDRESS_MAP             (~(KLDRADDR)2)
+
+/** Special import module ordinal value used to indicate that there is no
+ * specific module associated with the requested symbol. */
+#define NIL_KLDRMOD_IMPORT                  (~(KU32)0)
+
+/** Special symbol ordinal value used to indicate that the symbol
+ * only has a string name. */
+#define NIL_KLDRMOD_SYM_ORDINAL             (~(KU32)0)
+
+
+/** @name Load symbol kind flags.
+ * @{ */
+/** The bitness doesn't matter. */
+#define KLDRSYMKIND_NO_BIT                  0x00000000
+/** 16-bit symbol. */
+#define KLDRSYMKIND_16BIT                   0x00000001
+/** 32-bit symbol. */
+#define KLDRSYMKIND_32BIT                   0x00000002
+/** 64-bit symbol. */
+#define KLDRSYMKIND_64BIT                   0x00000003
+/** Mask out the bit.*/
+#define KLDRSYMKIND_BIT_MASK                0x00000003
+/** We don't know the type of symbol. */
+#define KLDRSYMKIND_NO_TYPE                 0x00000000
+/** The symbol is a code object (method/function/procedure/whateveryouwannacallit). */
+#define KLDRSYMKIND_CODE                    0x00000010
+/** The symbol is a data object. */
+#define KLDRSYMKIND_DATA                    0x00000020
+/** Mask out the symbol type. */
+#define KLDRSYMKIND_TYPE_MASK               0x00000030
+/** Valid symbol kind mask. */
+#define KLDRSYMKIND_MASK                    0x00000033
+/** Weak symbol. */
+#define KLDRSYMKIND_WEAK                    0x00000100
+/** Forwarder symbol. */
+#define KLDRSYMKIND_FORWARDER               0x00000200
+/** Request a flat symbol address. */
+#define KLDRSYMKIND_REQ_FLAT                0x00000000
+/** Request a segmented symbol address. */
+#define KLDRSYMKIND_REQ_SEGMENTED           0x40000000
+/** Request type mask. */
+#define KLDRSYMKIND_REQ_TYPE_MASK           0x40000000
+/** @} */
+
+/** @name kLdrModEnumSymbols flags.
+ * @{ */
+/** Returns ALL kinds of symbols. The default is to only return public/exported symbols. */
+#define KLDRMOD_ENUM_SYMS_FLAGS_ALL         0x00000001
+/** @} */
+
+
+/**
+ * Callback for resolving imported symbols when applying fixups.
+ *
+ * @returns 0 on success and *pValue and *pfKind filled.
+ * @returns Non-zero OS specific or kLdr status code on failure.
+ *
+ * @param   pMod        The module which fixups are begin applied.
+ * @param   iImport     The import module ordinal number or NIL_KLDRMOD_IMPORT.
+ * @param   iSymbol     The symbol ordinal number or NIL_KLDRMOD_SYM_ORDINAL.
+ * @param   pchSymbol   The symbol name. Can be NULL if iSymbol isn't nil. Doesn't have to be null-terminated.
+ * @param   cchSymbol   The length of the symbol.
+ * @param   pszVersion  The symbol version. NULL if not versioned.
+ * @param   puValue     Where to store the symbol value.
+ * @param   pfKind      Where to store the symbol kind flags.
+ * @param   pvUser      The user parameter specified to the relocation function.
+ */
+typedef int FNKLDRMODGETIMPORT(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
+                               const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser);
+/** Pointer to a import callback. */
+typedef FNKLDRMODGETIMPORT *PFNKLDRMODGETIMPORT;
+
+/**
+ * Symbol enumerator callback.
+ *
+ * @returns 0 if enumeration should continue.
+ * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumSymbols().
+ *
+ * @param   pMod        The module which symbols are being enumerated.s
+ * @param   iSymbol     The symbol ordinal number or NIL_KLDRMOD_SYM_ORDINAL.
+ * @param   pchSymbol   The symbol name. This can be NULL if there is a symbol ordinal.
+ *                      This can also be an empty string if the symbol doesn't have a name
+ *                      or it's name has been stripped.
+ *                      Important, this doesn't have to be a null-terminated string.
+ * @param   cchSymbol   The length of the symbol.
+ * @param   pszVersion  The symbol version. NULL if not versioned.
+ * @param   uValue      The symbol value.
+ * @param   fKind       The symbol kind flags.
+ * @param   pvUser      The user parameter specified to kLdrModEnumSymbols().
+ */
+typedef int FNKLDRMODENUMSYMS(PKLDRMOD pMod, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                              KLDRADDR uValue, KU32 fKind, void *pvUser);
+/** Pointer to a symbol enumerator callback. */
+typedef FNKLDRMODENUMSYMS *PFNKLDRMODENUMSYMS;
+
+/**
+ * Debug info enumerator callback.
+ *
+ * @returns 0 to continue the enumeration.
+ * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumDbgInfo().
+ *
+ * @param   pMod        The module.
+ * @param   iDbgInfo    The debug info ordinal number / id.
+ * @param   enmType     The debug info type.
+ * @param   iMajorVer   The major version number of the debug info format. -1 if unknow - implies invalid iMinorVer.
+ * @param   iMinorVer   The minor version number of the debug info format. -1 when iMajorVer is -1.
+ * @param   offFile     The file offset *if* this type has one specific location in the executable image file.
+ *                      This is -1 if there isn't any specific file location.
+ * @param   LinkAddress The link address of the debug info if it's loadable. NIL_KLDRADDR if not loadable.
+ * @param   cb          The size of the debug information. -1 is used if this isn't applicable.
+ * @param   pszExtFile  This points to the name of an external file containing the debug info.
+ *                      This is NULL if there isn't any external file.
+ * @param   pvUser      The user parameter specified to kLdrModEnumDbgInfo.
+ */
+typedef int FNKLDRENUMDBG(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType, KI16 iMajorVer, KI16 iMinorVer,
+                          KLDRFOFF offFile, KLDRADDR LinkAddress, KLDRSIZE cb, const char *pszExtFile, void *pvUser);
+/** Pointer to a debug info enumerator callback. */
+typedef FNKLDRENUMDBG *PFNKLDRENUMDBG;
+
+/**
+ * Resource enumerator callback.
+ *
+ * @returns 0 to continue the enumeration.
+ * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumResources().
+ *
+ * @param   pMod        The module.
+ * @param   idType      The resource type id. NIL_KLDRMOD_RSRC_TYPE_ID if no type id.
+ * @param   pszType     The resource type name. NULL if no type name.
+ * @param   idName      The resource id. NIL_KLDRMOD_RSRC_NAME_ID if no id.
+ * @param   pszName     The resource name. NULL if no name.
+ * @param   idLang      The language id.
+ * @param   AddrRsrc    The address value for the resource.
+ * @param   cbRsrc      The size of the resource.
+ * @param   pvUser      The user parameter specified to kLdrModEnumDbgInfo.
+ */
+typedef int FNKLDRENUMRSRC(PKLDRMOD pMod, KU32 idType, const char *pszType, KU32 idName, const char *pszName,
+                           KU32 idLang, KLDRADDR AddrRsrc, KLDRSIZE cbRsrc, void *pvUser);
+/** Pointer to a resource enumerator callback. */
+typedef FNKLDRENUMRSRC *PFNKLDRENUMRSRC;
+
+/** NIL resource name ID. */
+#define NIL_KLDRMOD_RSRC_NAME_ID    ( ~(KU32)0 )
+/** NIL resource type ID. */
+#define NIL_KLDRMOD_RSRC_TYPE_ID    ( ~(KU32)0 )
+/** @name Language ID
+ *
+ * Except for the special IDs #defined here, the values are considered
+ * format specific for now since it's only used by the PE resources.
+ *
+ * @{ */
+/** NIL language ID. */
+#define NIL_KLDR_LANG_ID                ( ~(KU32)0 )
+/** Special language id value for matching any language. */
+#define KLDR_LANG_ID_ANY                ( ~(KU32)1 )
+/** Special language id value indicating language neutral. */
+#define KLDR_LANG_ID_NEUTRAL            ( ~(KU32)2 )
+/** Special language id value indicating user default language. */
+#define KLDR_LANG_ID_USER_DEFAULT       ( ~(KU32)3 )
+/** Special language id value indicating system default language. */
+#define KLDR_LANG_ID_SYS_DEFAULT        ( ~(KU32)4 )
+/** Special language id value indicating default custom locale. */
+#define KLDR_LANG_ID_CUSTOM_DEFAULT     ( ~(KU32)5 )
+/** Special language id value indicating unspecified custom locale. */
+#define KLDR_LANG_ID_CUSTOM_UNSPECIFIED ( ~(KU32)6 )
+/** Special language id value indicating default custom MUI locale. */
+#define KLDR_LANG_ID_UI_CUSTOM_DEFAULT  ( ~(KU32)7 )
+/** @} */
+
+
+int     kLdrModOpen(const char *pszFilename, PPKLDRMOD ppMod);
+int     kLdrModOpenFromRdr(PKRDR pRdr, PPKLDRMOD ppMod);
+int     kLdrModOpenNative(const char *pszFilename, PPKLDRMOD ppMod);
+int     kLdrModOpenNativeByHandle(KUPTR uHandle, PPKLDRMOD ppMod);
+int     kLdrModClose(PKLDRMOD pMod);
+
+int     kLdrModQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
+                           const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                           PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind);
+int     kLdrModEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
+                           KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
+int     kLdrModGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName);
+KI32    kLdrModNumberOfImports(PKLDRMOD pMod, const void *pvBits);
+int     kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu);
+int     kLdrModGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo);
+int     kLdrModQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress);
+int     kLdrModQueryResource(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType,
+                             KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc);
+int     kLdrModEnumResources(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType,
+                             KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser);
+int     kLdrModEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser);
+int     kLdrModHasDbgInfo(PKLDRMOD pMod, const void *pvBits);
+int     kLdrModMostlyDone(PKLDRMOD pMod);
+
+
+/** @name Operations On The Internally Managed Mapping
+ * @{ */
+int     kLdrModMap(PKLDRMOD pMod);
+int     kLdrModUnmap(PKLDRMOD pMod);
+int     kLdrModAllocTLS(PKLDRMOD pMod);
+void    kLdrModFreeTLS(PKLDRMOD pMod);
+int     kLdrModReload(PKLDRMOD pMod);
+int     kLdrModFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+int     kLdrModCallInit(PKLDRMOD pMod, KUPTR uHandle);
+int     kLdrModCallTerm(PKLDRMOD pMod, KUPTR uHandle);
+int     kLdrModCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching);
+/** @} */
+
+/** @name Operations On The Externally Managed Mappings
+ * @{ */
+KLDRADDR kLdrModSize(PKLDRMOD pMod);
+int     kLdrModGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+int     kLdrModRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                            PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+/** @} */
+
+
+/**
+ * The loader module operation.
+ */
+typedef struct KLDRMODOPS
+{
+    /** The name of this module interpreter. */
+    const char         *pszName;
+    /** Pointer to the next module interpreter. */
+    PCKLDRMODOPS        pNext;
+
+    /**
+     * Create a loader module instance interpreting the executable image found
+     * in the specified file provider instance.
+     *
+     * @returns 0 on success and *ppMod pointing to a module instance.
+     *          On failure, a non-zero OS specific error code is returned.
+     * @param   pOps            Pointer to the registered method table.
+     * @param   pRdr            The file provider instance to use.
+     * @param   offNewHdr       The offset of the new header in MZ files. -1 if not found.
+     * @param   ppMod           Where to store the module instance pointer.
+     */
+    int (* pfnCreate)(PCKLDRMODOPS pOps, PKRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod);
+    /**
+     * Destroys an loader module instance.
+     *
+     * The caller is responsible for calling kLdrModUnmap() and kLdrFreeTLS() first.
+     *
+     * @returns 0 on success, non-zero on failure. The module instance state
+     *          is unknown on failure, it's best not to touch it.
+     * @param   pMod    The module.
+     */
+    int (* pfnDestroy)(PKLDRMOD pMod);
+
+    /** @copydoc kLdrModQuerySymbol */
+    int (* pfnQuerySymbol)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
+                           const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                           PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind);
+    /** @copydoc kLdrModEnumSymbols */
+    int (* pfnEnumSymbols)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags,
+                           PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
+    /** @copydoc kLdrModGetImport */
+    int (* pfnGetImport)(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName);
+    /** @copydoc kLdrModNumberOfImports */
+    KI32 (* pfnNumberOfImports)(PKLDRMOD pMod, const void *pvBits);
+    /** @copydoc kLdrModCanExecuteOn */
+    int (* pfnCanExecuteOn)(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu);
+    /** @copydoc kLdrModGetStackInfo */
+    int (* pfnGetStackInfo)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo);
+    /** @copydoc kLdrModQueryMainEntrypoint */
+    int (* pfnQueryMainEntrypoint)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress);
+    /** @copydoc kLdrModQueryResource */
+    int (* pfnQueryResource)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType,
+                             KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc);
+    /** @copydoc kLdrModEnumResources */
+    int (* pfnEnumResources)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType,
+                             KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser);
+    /** @copydoc kLdrModEnumDbgInfo */
+    int (* pfnEnumDbgInfo)(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser);
+    /** @copydoc kLdrModHasDbgInfo */
+    int (* pfnHasDbgInfo)(PKLDRMOD pMod, const void *pvBits);
+    /** @copydoc kLdrModMap */
+    int (* pfnMap)(PKLDRMOD pMod);
+    /** @copydoc kLdrModUnmap */
+    int (* pfnUnmap)(PKLDRMOD pMod);
+    /** @copydoc kLdrModAllocTLS */
+    int (* pfnAllocTLS)(PKLDRMOD pMod);
+    /** @copydoc kLdrModFreeTLS */
+    void (*pfnFreeTLS)(PKLDRMOD pMod);
+    /** @copydoc kLdrModReload */
+    int (* pfnReload)(PKLDRMOD pMod);
+    /** @copydoc kLdrModFixupMapping */
+    int (* pfnFixupMapping)(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+    /** @copydoc kLdrModCallInit */
+    int (* pfnCallInit)(PKLDRMOD pMod, KUPTR uHandle);
+    /** @copydoc kLdrModCallTerm */
+    int (* pfnCallTerm)(PKLDRMOD pMod, KUPTR uHandle);
+    /** @copydoc kLdrModCallThread */
+    int (* pfnCallThread)(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching);
+    /** @copydoc kLdrModSize */
+    KLDRADDR (* pfnSize)(PKLDRMOD pMod);
+    /** @copydoc kLdrModGetBits */
+    int (* pfnGetBits)(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+    /** @copydoc kLdrModRelocateBits */
+    int (* pfnRelocateBits)(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                            PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+    /** @copydoc kLdrModMostlyDone */
+    int (* pfnMostlyDone)(PKLDRMOD pMod);
+    /** Dummy which should be assigned a non-zero value. */
+    KU32 uEndOfStructure;
+} KLDRMODOPS;
+
+
+/** @} */
+
+
+
+
+/** @defgroup grp_kLdrDyld   kLdrDyld - The dynamic loader
+ * @{ */
+
+/** The handle to a dynamic loader module. */
+typedef struct KLDRDYLDMOD *HKLDRMOD;
+/** Pointer to the handle to a dynamic loader module. */
+typedef HKLDRMOD *PHKLDRMOD;
+/** NIL handle value. */
+#define NIL_HKLDRMOD    ((HKLDRMOD)0)
+
+
+/**
+ * File search method.
+ *
+ * In addition to it's own way of finding files, kLdr emulates
+ * the methods employed by the most popular systems.
+ */
+typedef enum KLDRDYLDSEARCH
+{
+    /** The usual invalid file search method. */
+    KLDRDYLD_SEARCH_INVALID = 0,
+    /** Uses the kLdr file search method.
+     * @todo invent me. */
+    KLDRDYLD_SEARCH_KLDR,
+    /** Use the emulation closest to the host system. */
+    KLDRDYLD_SEARCH_HOST,
+    /** Emulate the OS/2 file search method.
+     * On non-OS/2 systems, BEGINLIBPATH, LIBPATH, ENDLIBPATH and LIBPATHSTRICT are
+     * taken form the environment. */
+    KLDRDYLD_SEARCH_OS2,
+    /** Emulate the standard window file search method. */
+    KLDRDYLD_SEARCH_WINDOWS,
+    /** Emulate the alternative window file search method. */
+    KLDRDYLD_SEARCH_WINDOWS_ALTERED,
+    /** Emulate the most common UNIX file search method. */
+    KLDRDYLD_SEARCH_UNIX_COMMON,
+    /** End of the valid file search method values. */
+    KLDRDYLD_SEARCH_END,
+    /** Hack to blow the type up to 32-bit. */
+    KLDRDYLD_SEARCH_32BIT_HACK = 0x7fffffff
+} KLDRDYLDSEARCH;
+
+/** @name kLdrDyldLoad and kLdrDyldFindByName flags.
+ * @{ */
+/** The symbols in the module should be loaded into the global unix namespace.
+ * If not specified, the symbols are local and can only be referenced directly. */
+#define KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS      0x00000001
+/** The symbols in the module should be loaded into the global unix namespace and
+ * it's symbols should take precedence over all currently loaded modules.
+ * This implies KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS. */
+#define KLDRYDLD_LOAD_FLAGS_DEEP_SYMBOLS        0x00000002
+/** The module shouldn't be found by a global module search.
+ * If not specified, the module can be found by unspecified module searches,
+ * typical used when loading import/dep modules. */
+#define KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE     0x00000004
+/** Do a recursive initialization calls instead of defering them to the outermost call. */
+#define KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT      0x00000008
+/** We're loading the executable module.
+ * @internal */
+#define KLDRDYLD_LOAD_FLAGS_EXECUTABLE          0x40000000
+/** @} */
+
+
+int     kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                     unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr);
+int     kLdrDyldUnload(HKLDRMOD hMod);
+int     kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                           unsigned fFlags, PHKLDRMOD phMod);
+int     kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment);
+int     kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName);
+int     kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename);
+int     kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName,
+                            const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind);
+int     kLdrDyldQueryResource(HKLDRMOD hMod, KU32 idType, const char *pszType, KU32 idName,
+                              const char *pszName, KU32 idLang, void **pvRsrc, KSIZE *pcbRsrc);
+int     kLdrDyldEnumResources(HKLDRMOD hMod, KU32 idType, const char *pszType, KU32 idName,
+                              const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser);
+
+
+/** @name OS/2 like API
+ * @{ */
+#if defined(__OS2__)
+# define KLDROS2API _System
+#else
+# define KLDROS2API
+#endif
+int     kLdrDosLoadModule(char *pszObject, KSIZE cbObject, const char *pszModule, PHKLDRMOD phMod);
+int     kLdrDosFreeModule(HKLDRMOD hMod);
+int     kLdrDosQueryModuleHandle(const char *pszModname, PHKLDRMOD phMod);
+int     kLdrDosQueryModuleName(HKLDRMOD hMod, KSIZE cchName, char *pszName);
+int     kLdrDosQueryProcAddr(HKLDRMOD hMod, KU32 iOrdinal, const char *pszProcName, void **ppvProcAddr);
+int     kLdrDosQueryProcType(HKLDRMOD hMod, KU32 iOrdinal, const char *pszProcName, KU32 *pfProcType);
+int     kLdrDosQueryModFromEIP(PHKLDRMOD phMod, KU32 *piObject, KSIZE cbName, char *pszName, KUPTR *poffObject, KUPTR ulEIP);
+int     kLdrDosReplaceModule(const char *pszOldModule, const char *pszNewModule, const char *pszBackupModule);
+int     kLdrDosGetResource(HKLDRMOD hMod, KU32 idType, KU32 idName, void **pvResAddr);
+int     kLdrDosQueryResourceSize(HKLDRMOD hMod, KU32 idType, KU32 idName, KU32 *pcb);
+int     kLdrDosFreeResource(void *pvResAddr);
+/** @} */
+
+/** @name POSIX like API
+ * @{ */
+HKLDRMOD    kLdrDlOpen(const char *pszLibrary, int fFlags);
+const char *kLdrDlError(void);
+void *      kLdrDlSym(HKLDRMOD hMod, const char *pszSymbol);
+int         kLdrDlClose(HKLDRMOD hMod);
+/** @todo GNU extensions */
+/** @} */
+
+/** @name Win32 like API
+ * @{ */
+#if defined(_MSC_VER)
+# define KLDRWINAPI __stdcall
+#else
+# define KLDRWINAPI
+#endif
+HKLDRMOD KLDRWINAPI kLdrWLoadLibrary(const char *pszFilename);
+HKLDRMOD KLDRWINAPI kLdrWLoadLibraryEx(const char *pszFilename, void *hFileReserved, KU32 fFlags);
+KU32     KLDRWINAPI kLdrWGetModuleFileName(HKLDRMOD hMod, char *pszModName, KSIZE cchModName);
+HKLDRMOD KLDRWINAPI kLdrWGetModuleHandle(const char *pszFilename);
+int      KLDRWINAPI kLdrWGetModuleHandleEx(KU32 fFlags, const char *pszFilename, HKLDRMOD hMod);
+void *   KLDRWINAPI kLdrWGetProcAddress(HKLDRMOD hMod, const char *pszProcName);
+KU32     KLDRWINAPI kLdrWGetDllDirectory(KSIZE cchDir, char *pszDir);
+int      KLDRWINAPI kLdrWSetDllDirectory(const char *pszDir);
+int      KLDRWINAPI kLdrWFreeLibrary(HKLDRMOD hMod);
+int      KLDRWINAPI kLdrWDisableThreadLibraryCalls(HKLDRMOD hMod);
+
+/** The handle to a resource that's been found. */
+typedef struct KLDRWRSRCFOUND *HKLDRWRSRCFOUND;
+/** The handle to a loaded resource. */
+typedef struct KLDRWRSRCLOADED *HKLDRWRSRCLOADED;
+HKLDRWRSRCFOUND  KLDRWINAPI kLdrWFindResource(HKLDRMOD hMod, const char *pszType, const char *pszName);
+HKLDRWRSRCFOUND  KLDRWINAPI kLdrWFindResourceEx(HKLDRMOD hMod, const char *pszType, const char *pszName, KU16 idLang);
+KU32             KLDRWINAPI kLdrWSizeofResource(HKLDRMOD hMod, HKLDRWRSRCFOUND hFoundRsrc);
+HKLDRWRSRCLOADED KLDRWINAPI kLdrWLoadResource(HKLDRMOD hMod, HKLDRWRSRCFOUND hFoundRsrc);
+void    *KLDRWINAPI kLdrWLockResource(HKLDRMOD hMod, HKLDRWRSRCLOADED hLoadedRsrc);
+int      KLDRWINAPI kLdrWFreeResource(HKLDRMOD hMod, HKLDRWRSRCLOADED hLoadedRsrc);
+
+typedef int (KLDRWINAPI *PFNKLDRWENUMRESTYPE)(HKLDRMOD hMod, const char *pszType, KUPTR uUser);
+int      KLDRWINAPI kLdrWEnumResourceTypes(HKLDRMOD hMod, PFNKLDRWENUMRESTYPE pfnEnum, KUPTR uUser);
+int      KLDRWINAPI kLdrWEnumResourceTypesEx(HKLDRMOD hMod, PFNKLDRWENUMRESTYPE pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang);
+
+typedef int (KLDRWINAPI *PFNKLDRWENUMRESNAME)(HKLDRMOD hMod, const char *pszType, char *pszName, KUPTR uUser);
+int      KLDRWINAPI kLdrWEnumResourceNames(HKLDRMOD hMod, const char *pszType, PFNKLDRWENUMRESNAME pfnEnum, KUPTR uUser);
+int      KLDRWINAPI kLdrWEnumResourceNamesEx(HKLDRMOD hMod, const char *pszType, PFNKLDRWENUMRESNAME pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang);
+
+typedef int (KLDRWINAPI *PFNKLDRWENUMRESLANG)(HKLDRMOD hMod, const char *pszType, const char *pszName, KU16 idLang, KUPTR uUser);
+int      KLDRWINAPI kLdrWEnumResourceLanguages(HKLDRMOD hMod, const char *pszType, const char *pszName, PFNKLDRWENUMRESLANG pfnEnum, KUPTR uUser);
+int      KLDRWINAPI kLdrWEnumResourceLanguagesEx(HKLDRMOD hMod, const char *pszType, const char *pszName,
+                                                 PFNKLDRWENUMRESLANG pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang);
+/** @} */
+
+
+/** @name Process Bootstrapping
+ * @{ */
+
+/**
+ * Argument package from the stub.
+ */
+typedef struct KLDREXEARGS
+{
+    /** Load & search flags, some which will become defaults. */
+    KU32            fFlags;
+    /** The default search method. */
+    KLDRDYLDSEARCH  enmSearch;
+    /** The executable file that the stub is supposed to load. */
+    char            szExecutable[260];
+    /** The default prefix used when searching for DLLs. */
+    char            szDefPrefix[16];
+    /** The default suffix used when searching for DLLs. */
+    char            szDefSuffix[16];
+    /** The LD_LIBRARY_PATH prefix for the process.. */
+    char            szLibPath[4096 - sizeof(KU32) - sizeof(KLDRDYLDSEARCH) - 16 - 16 - 260];
+} KLDREXEARGS, *PKLDREXEARGS;
+/** Pointer to a const argument package from the stub. */
+typedef const KLDREXEARGS *PCKLDREXEARGS;
+
+void kLdrLoadExe(PCKLDREXEARGS pArgs, void *pvOS); /** @todo fix this mess... */
+void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS);
+/** @} */
+
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
Index: /trunk/include/k/kLdrFmts/elf-amd64.h
===================================================================
--- /trunk/include/k/kLdrFmts/elf-amd64.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/elf-amd64.h	(revision 2)
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 1996-1997 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ */
+
+#ifndef ___k_kLdrFmts_elf_amd64_h___
+#define	___k_kLdrFmts_elf_amd64_h___
+
+/*
+ * ELF definitions for the AMD64 architecture.
+ */
+
+#if 0 /** @todo Auxiliary vector entries. */
+/*
+ * Auxiliary vector entries for passing information to the interpreter.
+ *
+ * The i386 supplement to the SVR4 ABI specification names this "auxv_t",
+ * but POSIX lays claim to all symbols ending with "_t".
+ */
+typedef struct {	/* Auxiliary vector entry on initial stack */
+	int	a_type;			/* Entry type. */
+	union {
+		int	a_val;		/* Integer value. */
+	} a_un;
+} Elf32_Auxinfo;
+
+
+typedef struct {	/* Auxiliary vector entry on initial stack */
+	long	a_type;			/* Entry type. */
+	union {
+		long	a_val;		/* Integer value. */
+		void	*a_ptr;		/* Address. */
+		void	(*a_fcn)(void);	/* Function pointer (not used). */
+	} a_un;
+} Elf64_Auxinfo;
+
+__ElfType(Auxinfo);
+
+/* Values for a_type. */
+#define	AT_NULL		0	/* Terminates the vector. */
+#define	AT_IGNORE	1	/* Ignored entry. */
+#define	AT_EXECFD	2	/* File descriptor of program to load. */
+#define	AT_PHDR		3	/* Program header of program already loaded. */
+#define	AT_PHENT	4	/* Size of each program header entry. */
+#define	AT_PHNUM	5	/* Number of program header entries. */
+#define	AT_PAGESZ	6	/* Page size in bytes. */
+#define	AT_BASE		7	/* Interpreter's base address. */
+#define	AT_FLAGS	8	/* Flags (unused for i386). */
+#define	AT_ENTRY	9	/* Where interpreter should transfer control. */
+
+/*
+ * The following non-standard values are used for passing information
+ * from John Polstra's testbed program to the dynamic linker.  These
+ * are expected to go away soon.
+ *
+ * Unfortunately, these overlap the Linux non-standard values, so they
+ * must not be used in the same context.
+ */
+#define	AT_BRK		10	/* Starting point for sbrk and brk. */
+#define	AT_DEBUG	11	/* Debugging level. */
+
+/*
+ * The following non-standard values are used in Linux ELF binaries.
+ */
+#define	AT_NOTELF	10	/* Program is not ELF ?? */
+#define	AT_UID		11	/* Real uid. */
+#define	AT_EUID		12	/* Effective uid. */
+#define	AT_GID		13	/* Real gid. */
+#define	AT_EGID		14	/* Effective gid. */
+
+#define	AT_COUNT	15	/* Count of defined aux entry types. */
+
+#endif /* [todo] */
+
+/*
+ * Relocation types.
+ */
+
+#define	R_X86_64_NONE	0	/* No relocation. */
+#define	R_X86_64_64	1	/* Add 64 bit symbol value. */
+#define	R_X86_64_PC32	2	/* PC-relative 32 bit signed sym value. */
+#define	R_X86_64_GOT32	3	/* PC-relative 32 bit GOT offset. */
+#define	R_X86_64_PLT32	4	/* PC-relative 32 bit PLT offset. */
+#define	R_X86_64_COPY	5	/* Copy data from shared object. */
+#define	R_X86_64_GLOB_DAT 6	/* Set GOT entry to data address. */
+#define	R_X86_64_JMP_SLOT 7	/* Set GOT entry to code address. */
+#define	R_X86_64_RELATIVE 8	/* Add load address of shared object. */
+#define	R_X86_64_GOTPCREL 9	/* Add 32 bit signed pcrel offset to GOT. */
+#define	R_X86_64_32	10	/* Add 32 bit zero extended symbol value */
+#define	R_X86_64_32S	11	/* Add 32 bit sign extended symbol value */
+#define	R_X86_64_16	12	/* Add 16 bit zero extended symbol value */
+#define	R_X86_64_PC16	13	/* Add 16 bit signed extended pc relative symbol value */
+#define	R_X86_64_8	14	/* Add 8 bit zero extended symbol value */
+#define	R_X86_64_PC8	15	/* Add 8 bit signed extended pc relative symbol value */
+#define	R_X86_64_DTPMOD64 16	/* ID of module containing symbol */
+#define	R_X86_64_DTPOFF64 17	/* Offset in TLS block */
+#define	R_X86_64_TPOFF64 18	/* Offset in static TLS block */
+#define	R_X86_64_TLSGD	19	/* PC relative offset to GD GOT entry */
+#define	R_X86_64_TLSLD	20	/* PC relative offset to LD GOT entry */
+#define	R_X86_64_DTPOFF32 21	/* Offset in TLS block */
+#define	R_X86_64_GOTTPOFF 22	/* PC relative offset to IE GOT entry */
+#define	R_X86_64_TPOFF32 23	/* Offset in static TLS block */
+
+#define	R_X86_64_COUNT	24	/* Count of defined relocation types. */
+
+#endif
+
Index: /trunk/include/k/kLdrFmts/elf-i386.h
===================================================================
--- /trunk/include/k/kLdrFmts/elf-i386.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/elf-i386.h	(revision 2)
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 1996-1997 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
+ */
+
+#ifndef ___k_kLdrFmts_elf_i386_h___
+#define ___k_kLdrFmts_elf_i386_h___
+
+#if 0 /** @todo Auxiliary vector entries. */
+
+/*
+ * Auxiliary vector entries for passing information to the interpreter.
+ *
+ * The i386 supplement to the SVR4 ABI specification names this "auxv_t",
+ * but POSIX lays claim to all symbols ending with "_t".
+ */
+
+typedef struct {	/* Auxiliary vector entry on initial stack */
+	int	a_type;			/* Entry type. */
+	union {
+		long	a_val;		/* Integer value. */
+		void	*a_ptr;		/* Address. */
+		void	(*a_fcn)(void);	/* Function pointer (not used). */
+	} a_un;
+} Elf32_Auxinfo;
+
+#if __ELF_WORD_SIZE == 64
+/* Fake for amd64 loader support */
+typedef struct {
+	int fake;
+} Elf64_Auxinfo;
+#endif
+
+/* Values for a_type. */
+#define	AT_NULL		0	/* Terminates the vector. */
+#define	AT_IGNORE	1	/* Ignored entry. */
+#define	AT_EXECFD	2	/* File descriptor of program to load. */
+#define	AT_PHDR		3	/* Program header of program already loaded. */
+#define	AT_PHENT	4	/* Size of each program header entry. */
+#define	AT_PHNUM	5	/* Number of program header entries. */
+#define	AT_PAGESZ	6	/* Page size in bytes. */
+#define	AT_BASE		7	/* Interpreter's base address. */
+#define	AT_FLAGS	8	/* Flags (unused for i386). */
+#define	AT_ENTRY	9	/* Where interpreter should transfer control. */
+
+/*
+ * The following non-standard values are used for passing information
+ * from John Polstra's testbed program to the dynamic linker.  These
+ * are expected to go away soon.
+ *
+ * Unfortunately, these overlap the Linux non-standard values, so they
+ * must not be used in the same context.
+ */
+#define	AT_BRK		10	/* Starting point for sbrk and brk. */
+#define	AT_DEBUG	11	/* Debugging level. */
+
+/*
+ * The following non-standard values are used in Linux ELF binaries.
+ */
+#define	AT_NOTELF	10	/* Program is not ELF ?? */
+#define	AT_UID		11	/* Real uid. */
+#define	AT_EUID		12	/* Effective uid. */
+#define	AT_GID		13	/* Real gid. */
+#define	AT_EGID		14	/* Effective gid. */
+
+#define	AT_COUNT	15	/* Count of defined aux entry types. */
+
+#endif /* [todo] */
+
+
+/*
+ * Relocation types.
+ */
+
+#define	R_386_NONE	0	/* No relocation. */
+#define	R_386_32	1	/* Add symbol value. */
+#define	R_386_PC32	2	/* Add PC-relative symbol value. */
+#define	R_386_GOT32	3	/* Add PC-relative GOT offset. */
+#define	R_386_PLT32	4	/* Add PC-relative PLT offset. */
+#define	R_386_COPY	5	/* Copy data from shared object. */
+#define	R_386_GLOB_DAT	6	/* Set GOT entry to data address. */
+#define	R_386_JMP_SLOT	7	/* Set GOT entry to code address. */
+#define	R_386_RELATIVE	8	/* Add load address of shared object. */
+#define	R_386_GOTOFF	9	/* Add GOT-relative symbol address. */
+#define	R_386_GOTPC	10	/* Add PC-relative GOT table address. */
+#define	R_386_TLS_TPOFF	14	/* Negative offset in static TLS block */
+#define	R_386_TLS_IE	15	/* Absolute address of GOT for -ve static TLS */
+#define	R_386_TLS_GOTIE	16	/* GOT entry for negative static TLS block */
+#define	R_386_TLS_LE	17	/* Negative offset relative to static TLS */
+#define	R_386_TLS_GD	18	/* 32 bit offset to GOT (index,off) pair */
+#define	R_386_TLS_LDM	19	/* 32 bit offset to GOT (index,zero) pair */
+#define	R_386_TLS_GD_32	24	/* 32 bit offset to GOT (index,off) pair */
+#define	R_386_TLS_GD_PUSH 25	/* pushl instruction for Sun ABI GD sequence */
+#define	R_386_TLS_GD_CALL 26	/* call instruction for Sun ABI GD sequence */
+#define	R_386_TLS_GD_POP 27	/* popl instruction for Sun ABI GD sequence */
+#define	R_386_TLS_LDM_32 28	/* 32 bit offset to GOT (index,zero) pair */
+#define	R_386_TLS_LDM_PUSH 29	/* pushl instruction for Sun ABI LD sequence */
+#define	R_386_TLS_LDM_CALL 30	/* call instruction for Sun ABI LD sequence */
+#define	R_386_TLS_LDM_POP 31	/* popl instruction for Sun ABI LD sequence */
+#define	R_386_TLS_LDO_32 32	/* 32 bit offset from start of TLS block */
+#define	R_386_TLS_IE_32	33	/* 32 bit offset to GOT static TLS offset entry */
+#define	R_386_TLS_LE_32	34	/* 32 bit offset within static TLS block */
+#define	R_386_TLS_DTPMOD32 35	/* GOT entry containing TLS index */
+#define	R_386_TLS_DTPOFF32 36	/* GOT entry containing TLS offset */
+#define	R_386_TLS_TPOFF32 37	/* GOT entry of -ve static TLS offset */
+
+#define	R_386_COUNT	38	/* Count of defined relocation types. */
+
+#endif
+
Index: /trunk/include/k/kLdrFmts/elf32.h
===================================================================
--- /trunk/include/k/kLdrFmts/elf32.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/elf32.h	(revision 2)
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 1996-1998 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8 2002/05/30 08:32:18 dfr Exp $
+ */
+
+#ifndef ___k_kLdrFmts_elf32_h___
+#define ___k_kLdrFmts_elf32_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kLdrFmts/elf_common.h>
+
+/*
+ * ELF definitions common to all 32-bit architectures.
+ */
+
+typedef KU32	Elf32_Addr;
+typedef KU16	Elf32_Half;
+typedef KU32	Elf32_Off;
+typedef KI32		Elf32_Sword;
+typedef KU32	Elf32_Word;
+typedef KU32	Elf32_Size;
+typedef Elf32_Off	Elf32_Hashelt;
+
+/*
+ * ELF header.
+ */
+
+typedef struct Elf32_Ehdr {
+	unsigned char	e_ident[EI_NIDENT];	/* File identification. */
+	Elf32_Half	e_type;		/* File type. */
+	Elf32_Half	e_machine;	/* Machine architecture. */
+	Elf32_Word	e_version;	/* ELF format version. */
+	Elf32_Addr	e_entry;	/* Entry point. */
+	Elf32_Off	e_phoff;	/* Program header file offset. */
+	Elf32_Off	e_shoff;	/* Section header file offset. */
+	Elf32_Word	e_flags;	/* Architecture-specific flags. */
+	Elf32_Half	e_ehsize;	/* Size of ELF header in bytes. */
+	Elf32_Half	e_phentsize;	/* Size of program header entry. */
+	Elf32_Half	e_phnum;	/* Number of program header entries. */
+	Elf32_Half	e_shentsize;	/* Size of section header entry. */
+	Elf32_Half	e_shnum;	/* Number of section header entries. */
+	Elf32_Half	e_shstrndx;	/* Section name strings section. */
+} Elf32_Ehdr;
+
+/*
+ * Section header.
+ */
+
+typedef struct {
+	Elf32_Word	sh_name;	/* Section name (index into the
+					   section header string table). */
+	Elf32_Word	sh_type;	/* Section type. */
+	Elf32_Word	sh_flags;	/* Section flags. */
+	Elf32_Addr	sh_addr;	/* Address in memory image. */
+	Elf32_Off	sh_offset;	/* Offset in file. */
+	Elf32_Size	sh_size;	/* Size in bytes. */
+	Elf32_Word	sh_link;	/* Index of a related section. */
+	Elf32_Word	sh_info;	/* Depends on section type. */
+	Elf32_Size	sh_addralign;	/* Alignment in bytes. */
+	Elf32_Size	sh_entsize;	/* Size of each entry in section. */
+} Elf32_Shdr;
+
+/*
+ * Program header.
+ */
+
+typedef struct {
+	Elf32_Word	p_type;		/* Entry type. */
+	Elf32_Off	p_offset;	/* File offset of contents. */
+	Elf32_Addr	p_vaddr;	/* Virtual address in memory image. */
+	Elf32_Addr	p_paddr;	/* Physical address (not used). */
+	Elf32_Size	p_filesz;	/* Size of contents in file. */
+	Elf32_Size	p_memsz;	/* Size of contents in memory. */
+	Elf32_Word	p_flags;	/* Access permission flags. */
+	Elf32_Size	p_align;	/* Alignment in memory and file. */
+} Elf32_Phdr;
+
+/*
+ * Dynamic structure.  The ".dynamic" section contains an array of them.
+ */
+
+typedef struct {
+	Elf32_Sword	d_tag;		/* Entry type. */
+	union {
+		Elf32_Size	d_val;	/* Integer value. */
+		Elf32_Addr	d_ptr;	/* Address value. */
+	} d_un;
+} Elf32_Dyn;
+
+/*
+ * Relocation entries.
+ */
+
+/* Relocations that don't need an addend field. */
+typedef struct {
+	Elf32_Addr	r_offset;	/* Location to be relocated. */
+	Elf32_Word	r_info;		/* Relocation type and symbol index. */
+} Elf32_Rel;
+
+/* Relocations that need an addend field. */
+typedef struct {
+	Elf32_Addr	r_offset;	/* Location to be relocated. */
+	Elf32_Word	r_info;		/* Relocation type and symbol index. */
+	Elf32_Sword	r_addend;	/* Addend. */
+} Elf32_Rela;
+
+/* Macros for accessing the fields of r_info. */
+#define ELF32_R_SYM(info)	((info) >> 8)
+#define ELF32_R_TYPE(info)	((unsigned char)(info))
+
+/* Macro for constructing r_info from field values. */
+#define ELF32_R_INFO(sym, type)	(((sym) << 8) + (unsigned char)(type))
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+	Elf32_Word	st_name;	/* String table index of name. */
+	Elf32_Addr	st_value;	/* Symbol value. */
+	Elf32_Size	st_size;	/* Size of associated object. */
+	unsigned char	st_info;	/* Type and binding information. */
+	unsigned char	st_other;	/* Reserved (not used). */
+	Elf32_Half	st_shndx;	/* Section index of symbol. */
+} Elf32_Sym;
+
+/* Macros for accessing the fields of st_info. */
+#define ELF32_ST_BIND(info)		((info) >> 4)
+#define ELF32_ST_TYPE(info)		((info) & 0xf)
+
+/* Macro for constructing st_info from field values. */
+#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
+
+#endif
+
Index: /trunk/include/k/kLdrFmts/elf64.h
===================================================================
--- /trunk/include/k/kLdrFmts/elf64.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/elf64.h	(revision 2)
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 1996-1998 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/elf64.h,v 1.10 2002/05/30 08:32:18 dfr Exp $
+ */
+
+#ifndef ___k_kLdrFmts_elf64_h___
+#define ___k_kLdrFmts_elf64_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+#include <k/kLdrFmts/elf_common.h>
+
+/*
+ * ELF definitions common to all 64-bit architectures.
+ */
+
+typedef KU64    Elf64_Addr;
+typedef KU32    Elf64_Half;
+typedef KU64    Elf64_Off;
+typedef KI64    Elf64_Sword;
+typedef KU64    Elf64_Word;
+typedef KU64    Elf64_Size;
+typedef KU16    Elf64_Quarter;
+
+/*
+ * Types of dynamic symbol hash table bucket and chain elements.
+ *
+ * This is inconsistent among 64 bit architectures, so a machine dependent
+ * typedef is required.
+ */
+
+#ifdef __alpha__
+typedef Elf64_Off	Elf64_Hashelt;
+#else
+typedef Elf64_Half	Elf64_Hashelt;
+#endif
+
+/*
+ * ELF header.
+ */
+
+typedef struct {
+	unsigned char	e_ident[EI_NIDENT];	/* File identification. */
+	Elf64_Quarter	e_type;		/* File type. */
+	Elf64_Quarter	e_machine;	/* Machine architecture. */
+	Elf64_Half	e_version;	/* ELF format version. */
+	Elf64_Addr	e_entry;	/* Entry point. */
+	Elf64_Off	e_phoff;	/* Program header file offset. */
+	Elf64_Off	e_shoff;	/* Section header file offset. */
+	Elf64_Half	e_flags;	/* Architecture-specific flags. */
+	Elf64_Quarter	e_ehsize;	/* Size of ELF header in bytes. */
+	Elf64_Quarter	e_phentsize;	/* Size of program header entry. */
+	Elf64_Quarter	e_phnum;	/* Number of program header entries. */
+	Elf64_Quarter	e_shentsize;	/* Size of section header entry. */
+	Elf64_Quarter	e_shnum;	/* Number of section header entries. */
+	Elf64_Quarter	e_shstrndx;	/* Section name strings section. */
+} Elf64_Ehdr;
+
+/*
+ * Section header.
+ */
+
+typedef struct {
+	Elf64_Half	sh_name;	/* Section name (index into the
+					   section header string table). */
+	Elf64_Half	sh_type;	/* Section type. */
+	Elf64_Size	sh_flags;	/* Section flags. */
+	Elf64_Addr	sh_addr;	/* Address in memory image. */
+	Elf64_Off	sh_offset;	/* Offset in file. */
+	Elf64_Size	sh_size;	/* Size in bytes. */
+	Elf64_Half	sh_link;	/* Index of a related section. */
+	Elf64_Half	sh_info;	/* Depends on section type. */
+	Elf64_Size	sh_addralign;	/* Alignment in bytes. */
+	Elf64_Size	sh_entsize;	/* Size of each entry in section. */
+} Elf64_Shdr;
+
+/*
+ * Program header.
+ */
+
+typedef struct {
+	Elf64_Half	p_type;		/* Entry type. */
+	Elf64_Half	p_flags;	/* Access permission flags. */
+	Elf64_Off	p_offset;	/* File offset of contents. */
+	Elf64_Addr	p_vaddr;	/* Virtual address in memory image. */
+	Elf64_Addr	p_paddr;	/* Physical address (not used). */
+	Elf64_Size	p_filesz;	/* Size of contents in file. */
+	Elf64_Size	p_memsz;	/* Size of contents in memory. */
+	Elf64_Size	p_align;	/* Alignment in memory and file. */
+} Elf64_Phdr;
+
+/*
+ * Dynamic structure.  The ".dynamic" section contains an array of them.
+ */
+
+typedef struct {
+	Elf64_Size	d_tag;		/* Entry type. */
+	union {
+		Elf64_Size	d_val;	/* Integer value. */
+		Elf64_Addr	d_ptr;	/* Address value. */
+	} d_un;
+} Elf64_Dyn;
+
+/*
+ * Relocation entries.
+ */
+
+/* Relocations that don't need an addend field. */
+typedef struct {
+	Elf64_Addr	r_offset;	/* Location to be relocated. */
+	Elf64_Size	r_info;		/* Relocation type and symbol index. */
+} Elf64_Rel;
+
+/* Relocations that need an addend field. */
+typedef struct {
+	Elf64_Addr	r_offset;	/* Location to be relocated. */
+	Elf64_Size	r_info;		/* Relocation type and symbol index. */
+	Elf64_Off	r_addend;	/* Addend. */
+} Elf64_Rela;
+
+/* Macros for accessing the fields of r_info. */
+#define ELF64_R_SYM(info)	((info) >> 32)
+#define ELF64_R_TYPE(info)	((unsigned char)(info))
+
+/* Macro for constructing r_info from field values. */
+#define ELF64_R_INFO(sym, type)	(((sym) << 32) + (unsigned char)(type))
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+	Elf64_Half	st_name;	/* String table index of name. */
+	unsigned char	st_info;	/* Type and binding information. */
+	unsigned char	st_other;	/* Reserved (not used). */
+	Elf64_Quarter	st_shndx;	/* Section index of symbol. */
+	Elf64_Addr	st_value;	/* Symbol value. */
+	Elf64_Size	st_size;	/* Size of associated object. */
+} Elf64_Sym;
+
+/* Macros for accessing the fields of st_info. */
+#define ELF64_ST_BIND(info)		((info) >> 4)
+#define ELF64_ST_TYPE(info)		((info) & 0xf)
+
+/* Macro for constructing st_info from field values. */
+#define ELF64_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
+
+#endif
+
Index: /trunk/include/k/kLdrFmts/elf_common.h
===================================================================
--- /trunk/include/k/kLdrFmts/elf_common.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/elf_common.h	(revision 2)
@@ -0,0 +1,300 @@
+/*-
+ * Copyright (c) 1998 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.15 2004/05/05 02:38:54 marcel Exp $
+ */
+
+#ifndef ___k_kLdrFmts_elf_common_h___
+#define ___k_kLdrFmts_elf_common_h___
+
+/*
+ * ELF definitions that are independent of architecture or word size.
+ */
+
+/*
+ * Note header.  The ".note" section contains an array of notes.  Each
+ * begins with this header, aligned to a word boundary.  Immediately
+ * following the note header is n_namesz bytes of name, padded to the
+ * next word boundary.  Then comes n_descsz bytes of descriptor, again
+ * padded to a word boundary.  The values of n_namesz and n_descsz do
+ * not include the padding.
+ */
+
+typedef struct {
+	KU32	n_namesz;	/* Length of name. */
+	KU32	n_descsz;	/* Length of descriptor. */
+	KU32	n_type;		/* Type of this note. */
+} Elf_Note;
+
+/* Indexes into the e_ident array.  Keep synced with
+   http://www.sco.com/developer/gabi/ch4.eheader.html */
+#define EI_MAG0		0	/* Magic number, byte 0. */
+#define EI_MAG1		1	/* Magic number, byte 1. */
+#define EI_MAG2		2	/* Magic number, byte 2. */
+#define EI_MAG3		3	/* Magic number, byte 3. */
+#define EI_CLASS	4	/* Class of machine. */
+#define EI_DATA		5	/* Data format. */
+#define EI_VERSION	6	/* ELF format version. */
+#define EI_OSABI	7	/* Operating system / ABI identification */
+#define EI_ABIVERSION	8	/* ABI version */
+#define OLD_EI_BRAND	8	/* Start of architecture identification. */
+#define EI_PAD		9	/* Start of padding (per SVR4 ABI). */
+#define EI_NIDENT	16	/* Size of e_ident array. */
+
+/* Values for the magic number bytes. */
+#define ELFMAG0		0x7f
+#define ELFMAG1		'E'
+#define ELFMAG2		'L'
+#define ELFMAG3		'F'
+#define ELFMAG		"\177ELF"	/* magic string */
+#define SELFMAG		4		/* magic string size */
+
+/* Values for e_ident[EI_VERSION] and e_version. */
+#define EV_NONE		0
+#define EV_CURRENT	1
+
+/* Values for e_ident[EI_CLASS]. */
+#define ELFCLASSNONE	0	/* Unknown class. */
+#define ELFCLASS32	1	/* 32-bit architecture. */
+#define ELFCLASS64	2	/* 64-bit architecture. */
+
+/* Values for e_ident[EI_DATA]. */
+#define ELFDATANONE	0	/* Unknown data format. */
+#define ELFDATA2LSB	1	/* 2's complement little-endian. */
+#define ELFDATA2MSB	2	/* 2's complement big-endian. */
+
+/* Values for e_ident[EI_OSABI]. */
+#define ELFOSABI_SYSV		0	/* UNIX System V ABI */
+#define ELFOSABI_NONE		ELFOSABI_SYSV	/* symbol used in old spec */
+#define ELFOSABI_HPUX		1	/* HP-UX operating system */
+#define ELFOSABI_NETBSD		2	/* NetBSD */
+#define ELFOSABI_LINUX		3	/* GNU/Linux */
+#define ELFOSABI_HURD		4	/* GNU/Hurd */
+#define ELFOSABI_86OPEN		5	/* 86Open common IA32 ABI */
+#define ELFOSABI_SOLARIS	6	/* Solaris */
+#define ELFOSABI_MONTEREY	7	/* Monterey */
+#define ELFOSABI_IRIX		8	/* IRIX */
+#define ELFOSABI_FREEBSD	9	/* FreeBSD */
+#define ELFOSABI_TRU64		10	/* TRU64 UNIX */
+#define ELFOSABI_MODESTO	11	/* Novell Modesto */
+#define ELFOSABI_OPENBSD	12	/* OpenBSD */
+#define ELFOSABI_ARM		97	/* ARM */
+#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
+
+/* e_ident */
+#define IS_ELF(ehdr)	((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+			 (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+			 (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+			 (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* Values for e_type. */
+#define ET_NONE		0	/* Unknown type. */
+#define ET_REL		1	/* Relocatable. */
+#define ET_EXEC		2	/* Executable. */
+#define ET_DYN		3	/* Shared object. */
+#define ET_CORE		4	/* Core file. */
+
+/* Values for e_machine. */
+#define EM_NONE		0	/* Unknown machine. */
+#define EM_M32		1	/* AT&T WE32100. */
+#define EM_SPARC	2	/* Sun SPARC. */
+#define EM_386		3	/* Intel i386. */
+#define EM_68K		4	/* Motorola 68000. */
+#define EM_88K		5	/* Motorola 88000. */
+#define EM_486		6	/* Intel i486. */
+#define EM_860		7	/* Intel i860. */
+#define EM_MIPS		8	/* MIPS R3000 Big-Endian only */
+
+/* Extensions.  This list is not complete. */
+#define EM_S370		9	/* IBM System/370 */
+#define EM_MIPS_RS4_BE	10	/* MIPS R4000 Big-Endian */ /* Depreciated */
+#define EM_PARISC	15	/* HPPA */
+#define EM_SPARC32PLUS	18	/* SPARC v8plus */
+#define EM_PPC		20	/* PowerPC 32-bit */
+#define EM_PPC64	21	/* PowerPC 64-bit */
+#define EM_ARM		40	/* ARM */
+#define EM_SPARCV9	43	/* SPARC v9 64-bit */
+#define EM_IA_64	50	/* Intel IA-64 Processor */
+#define EM_X86_64	62	/* Advanced Micro Devices x86-64 */
+#define EM_ALPHA	0x9026	/* Alpha (written in the absence of an ABI */
+
+/* Special section indexes. */
+#define SHN_UNDEF	     0		/* Undefined, missing, irrelevant. */
+#define SHN_LORESERVE	0xff00		/* First of reserved range. */
+#define SHN_LOPROC	0xff00		/* First processor-specific. */
+#define SHN_HIPROC	0xff1f		/* Last processor-specific. */
+#define SHN_ABS		0xfff1		/* Absolute values. */
+#define SHN_COMMON	0xfff2		/* Common data. */
+#define SHN_HIRESERVE	0xffff		/* Last of reserved range. */
+
+/* sh_type */
+#define SHT_NULL	0		/* inactive */
+#define SHT_PROGBITS	1		/* program defined information */
+#define SHT_SYMTAB	2		/* symbol table section */
+#define SHT_STRTAB	3		/* string table section */
+#define SHT_RELA	4		/* relocation section with addends */
+#define SHT_HASH	5		/* symbol hash table section */
+#define SHT_DYNAMIC	6		/* dynamic section */
+#define SHT_NOTE	7		/* note section */
+#define SHT_NOBITS	8		/* no space section */
+#define SHT_REL		9		/* relocation section - no addends */
+#define SHT_SHLIB	10		/* reserved - purpose unknown */
+#define SHT_DYNSYM	11		/* dynamic symbol table section */
+#define SHT_NUM		12		/* number of section types */
+#define SHT_LOOS	0x60000000	/* First of OS specific semantics */
+#define SHT_HIOS	0x6fffffff	/* Last of OS specific semantics */
+#define SHT_LOPROC	0x70000000	/* reserved range for processor */
+#define SHT_HIPROC	0x7fffffff	/* specific section header types */
+#define SHT_LOUSER	0x80000000	/* reserved range for application */
+#define SHT_HIUSER	0xffffffff	/* specific indexes */
+
+/* Flags for sh_flags. */
+#define SHF_WRITE	0x1		/* Section contains writable data. */
+#define SHF_ALLOC	0x2		/* Section occupies memory. */
+#define SHF_EXECINSTR	0x4		/* Section contains instructions. */
+#define SHF_TLS		0x400		/* Section contains TLS data. */
+#define SHF_MASKPROC	0xf0000000	/* Reserved for processor-specific. */
+
+/* Values for p_type. */
+#define PT_NULL		0	/* Unused entry. */
+#define PT_LOAD		1	/* Loadable segment. */
+#define PT_DYNAMIC	2	/* Dynamic linking information segment. */
+#define PT_INTERP	3	/* Pathname of interpreter. */
+#define PT_NOTE		4	/* Auxiliary information. */
+#define PT_SHLIB	5	/* Reserved (not used). */
+#define PT_PHDR		6	/* Location of program header itself. */
+#define	PT_TLS		7	/* Thread local storage segment */
+
+#define PT_COUNT	8	/* Number of defined p_type values. */
+
+#define	PT_LOOS		0x60000000	/* OS-specific */
+#define	PT_HIOS		0x6fffffff	/* OS-specific */
+#define PT_LOPROC	0x70000000	/* First processor-specific type. */
+#define PT_HIPROC	0x7fffffff	/* Last processor-specific type. */
+
+/* Values for p_flags. */
+#define PF_X		0x1	/* Executable. */
+#define PF_W		0x2	/* Writable. */
+#define PF_R		0x4	/* Readable. */
+
+/* Values for d_tag. */
+#define DT_NULL		0	/* Terminating entry. */
+#define DT_NEEDED	1	/* String table offset of a needed shared
+				   library. */
+#define DT_PLTRELSZ	2	/* Total size in bytes of PLT relocations. */
+#define DT_PLTGOT	3	/* Processor-dependent address. */
+#define DT_HASH		4	/* Address of symbol hash table. */
+#define DT_STRTAB	5	/* Address of string table. */
+#define DT_SYMTAB	6	/* Address of symbol table. */
+#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
+#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
+#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
+#define DT_STRSZ	10	/* Size of string table. */
+#define DT_SYMENT	11	/* Size of each symbol table entry. */
+#define DT_INIT		12	/* Address of initialization function. */
+#define DT_FINI		13	/* Address of finalization function. */
+#define DT_SONAME	14	/* String table offset of shared object
+				   name. */
+#define DT_RPATH	15	/* String table offset of library path. [sup] */
+#define DT_SYMBOLIC	16	/* Indicates "symbolic" linking. [sup] */
+#define DT_REL		17	/* Address of ElfNN_Rel relocations. */
+#define DT_RELSZ	18	/* Total size of ElfNN_Rel relocations. */
+#define DT_RELENT	19	/* Size of each ElfNN_Rel relocation. */
+#define DT_PLTREL	20	/* Type of relocation used for PLT. */
+#define DT_DEBUG	21	/* Reserved (not used). */
+#define DT_TEXTREL	22	/* Indicates there may be relocations in
+				   non-writable segments. [sup] */
+#define DT_JMPREL	23	/* Address of PLT relocations. */
+#define	DT_BIND_NOW	24	/* [sup] */
+#define	DT_INIT_ARRAY	25	/* Address of the array of pointers to
+				   initialization functions */
+#define	DT_FINI_ARRAY	26	/* Address of the array of pointers to
+				   termination functions */
+#define	DT_INIT_ARRAYSZ	27	/* Size in bytes of the array of
+				   initialization functions. */
+#define	DT_FINI_ARRAYSZ	28	/* Size in bytes of the array of
+				   terminationfunctions. */
+#define	DT_RUNPATH	29	/* String table offset of a null-terminated
+				   library search path string. */
+#define	DT_FLAGS	30	/* Object specific flag values. */
+#define	DT_ENCODING	32	/* Values greater than or equal to DT_ENCODING
+				   and less than DT_LOOS follow the rules for
+				   the interpretation of the d_un union
+				   as follows: even == 'd_ptr', even == 'd_val'
+				   or none */
+#define	DT_PREINIT_ARRAY 32	/* Address of the array of pointers to
+				   pre-initialization functions. */
+#define	DT_PREINIT_ARRAYSZ 33	/* Size in bytes of the array of
+				   pre-initialization functions. */
+
+#define	DT_COUNT	33	/* Number of defined d_tag values. */
+
+#define	DT_LOOS		0x6000000d	/* First OS-specific */
+#define	DT_HIOS		0x6fff0000	/* Last OS-specific */
+#define	DT_LOPROC	0x70000000	/* First processor-specific type. */
+#define	DT_HIPROC	0x7fffffff	/* Last processor-specific type. */
+
+/* Values for DT_FLAGS */
+#define	DF_ORIGIN	0x0001	/* Indicates that the object being loaded may
+				   make reference to the $ORIGIN substitution
+				   string */
+#define	DF_SYMBOLIC	0x0002	/* Indicates "symbolic" linking. */
+#define	DF_TEXTREL	0x0004	/* Indicates there may be relocations in
+				   non-writable segments. */
+#define	DF_BIND_NOW	0x0008	/* Indicates that the dynamic linker should
+				   process all relocations for the object
+				   containing this entry before transferring
+				   control to the program. */
+#define	DF_STATIC_TLS	0x0010	/* Indicates that the shared object or
+				   executable contains code using a static
+				   thread-local storage scheme. */
+
+/* Values for n_type.  Used in core files. */
+#define NT_PRSTATUS	1	/* Process status. */
+#define NT_FPREGSET	2	/* Floating point registers. */
+#define NT_PRPSINFO	3	/* Process state info. */
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+#define STB_LOCAL	0	/* Local symbol */
+#define STB_GLOBAL	1	/* Global symbol */
+#define STB_WEAK	2	/* like global - lower precedence */
+#define STB_LOPROC	13	/* reserved range for processor */
+#define STB_HIPROC	15	/*  specific symbol bindings */
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+#define STT_NOTYPE	0	/* Unspecified type. */
+#define STT_OBJECT	1	/* Data object. */
+#define STT_FUNC	2	/* Function. */
+#define STT_SECTION	3	/* Section. */
+#define STT_FILE	4	/* Source file. */
+#define STT_TLS		6	/* TLS object. */
+#define STT_LOPROC	13	/* reserved range for processor */
+#define STT_HIPROC	15	/*  specific symbol types */
+
+/* Special symbol table indexes. */
+#define STN_UNDEF	0	/* Undefined symbol index. */
+
+#endif
+
Index: /trunk/include/k/kLdrFmts/lx.h
===================================================================
--- /trunk/include/k/kLdrFmts/lx.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/lx.h	(revision 2)
@@ -0,0 +1,460 @@
+/* $Id $ */
+/** @file
+ * LX structures, types and defines.
+ */
+
+#ifndef ___k_kLdrFmts_lx_h___
+#define ___k_kLdrFmts_lx_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+
+
+#ifndef IMAGE_OS2_SIGNATURE_LX
+/** LX signature ("LX") */
+# define IMAGE_LX_SIGNATURE  K_LE2H_U16('L' | ('X' << 8))
+#endif
+
+#pragma pack(1)
+
+/**
+ * Linear eXecutable header.
+ * This structure is exactly 196 bytes long.
+ */
+struct e32_exe
+{
+    KU8                 e32_magic[2];
+    KU8                 e32_border;
+    KU8                 e32_worder;
+    KU32                e32_level;
+    KU16                e32_cpu;
+    KU16                e32_os;
+    KU32                e32_ver;
+    KU32                e32_mflags;
+    KU32                e32_mpages;
+    KU32                e32_startobj;
+    KU32                e32_eip;
+    KU32                e32_stackobj;
+    KU32                e32_esp;
+    KU32                e32_pagesize;
+    KU32                e32_pageshift;
+    /** The size of the fixup section.
+     * The fixup section consists of the fixup page table, the fixup record table,
+     * the import module table, and the import procedure name table.
+     */
+    KU32                e32_fixupsize;
+    KU32                e32_fixupsum;
+    /** The size of the resident loader section.
+     * This includes the object table, the object page map table, the resource table, the resident name table,
+     * the entry table, the module format directives table, and the page checksum table (?). */
+    KU32                e32_ldrsize;
+    /** The checksum of the loader section. 0 if not calculated. */
+    KU32                e32_ldrsum;
+    /** The offset of the object table relative to this structure. */
+    KU32                e32_objtab;
+    /** Count of objects. */
+    KU32                e32_objcnt;
+    /** The offset of the object page map table relative to this structure. */
+    KU32                e32_objmap;
+    /** The offset of the object iterated pages (whatever this is used for) relative to the start of the file. */
+    KU32                e32_itermap;
+    /** The offset of the resource table relative to this structure. */
+    KU32                e32_rsrctab;
+    /** The number of entries in the resource table. */
+    KU32                e32_rsrccnt;
+    /** The offset of the resident name table relative to this structure. */
+    KU32                e32_restab;
+    /** The offset of the entry (export) table relative to this structure. */
+    KU32                e32_enttab;
+    /** The offset of the module format directives table relative to this structure. */
+    KU32                e32_dirtab;
+    /** The number of entries in the module format directives table. */
+    KU32                e32_dircnt;
+    /** The offset of the fixup page table relative to this structure. */
+    KU32                e32_fpagetab;
+    /** The offset of the fixup record table relative to this structure. */
+    KU32                e32_frectab;
+    /** The offset of the import module name table relative to this structure. */
+    KU32                e32_impmod;
+    /** The number of entries in the import module name table. */
+    KU32                e32_impmodcnt;
+    /** The offset of the import procedure name table relative to this structure. */
+    KU32                e32_impproc;
+    /** The offset of the page checksum table relative to this structure. */
+    KU32                e32_pagesum;
+    /** The offset of the data pages relative to the start of the file. */
+    KU32                e32_datapage;
+    /** The number of preload pages (ignored). */
+    KU32                e32_preload;
+    /** The offset of the non-resident name table relative to the start of the file. */
+    KU32                e32_nrestab;
+    /** The size of the non-resident name table. */
+    KU32                e32_cbnrestab;
+    KU32                e32_nressum;
+    KU32                e32_autodata;
+    KU32                e32_debuginfo;
+    KU32                e32_debuglen;
+    KU32                e32_instpreload;
+    KU32                e32_instdemand;
+    KU32                e32_heapsize;
+    KU32                e32_stacksize;
+    KU8                 e32_res3[20];
+};
+
+/** e32_magic[0] */
+#define E32MAGIC1       'L'
+/** e32_magic[1] */
+#define E32MAGIC2       'X'
+/** MAKEWORD(e32_magic[0], e32_magic[1]) */
+#define E32MAGIC        0x584c
+/** e32_border - little endian */
+#define E32LEBO         0
+/** e32_border - big endian */
+#define E32BEBO         1
+/** e32_worder - little endian */
+#define E32LEWO         0
+/** e32_worder - big endian */
+#define E32BEWO         1
+/** e32_level */
+#define E32LEVEL        KU32_C(0)
+/** e32_cpu - 80286 */
+#define E32CPU286       1
+/** e32_cpu - 80386 */
+#define E32CPU386       2
+/** e32_cpu - 80486 */
+#define E32CPU486       3
+/** e32_pagesize */
+#define OBJPAGELEN      KU32_C(0x1000)
+
+
+/** @name e32_mflags
+ * @{ */
+/** App Type: Fullscreen only. */
+#define E32NOPMW         KU32_C(0x00000100)
+/** App Type: PM API. */
+#define E32PMAPI         KU32_C(0x00000300)
+/** App Type: PM VIO compatible. */
+#define E32PMW           KU32_C(0x00000200)
+/** Application type mask. */
+#define E32APPMASK       KU32_C(0x00000300)
+/** Executable module. */
+#define E32MODEXE        KU32_C(0x00000000)
+/** Dynamic link library (DLL / library) module. */
+#define E32MODDLL        KU32_C(0x00008000)
+/** Protected memory DLL. */
+#define E32PROTDLL       KU32_C(0x00010000)
+/** Physical Device Driver. */
+#define E32MODPDEV       KU32_C(0x00020000)
+/** Virtual Device Driver. */
+#define E32MODVDEV       KU32_C(0x00028000)
+/** Device driver */
+#define E32DEVICE        E32MODPDEV
+/** Dynamic link library (DLL / library) module. */
+#define E32NOTP          E32MODDLL
+/** Protected memory DLL. */
+#define E32MODPROTDLL    (E32MODDLL | E32PROTDLL)
+/** Module Type mask. */
+#define E32MODMASK       KU32_C(0x00038000)
+/** Not loadable (linker error). */
+#define E32NOLOAD        KU32_C(0x00002000)
+/** No internal fixups. */
+#define E32NOINTFIX      KU32_C(0x00000010)
+/** No external fixups (i.e. imports). */
+#define E32NOEXTFIX      KU32_C(0x00000020)
+/** System DLL, no internal fixups. */
+#define E32SYSDLL        KU32_C(0x00000008)
+/** Global (set) or per instance (cleared) library initialization. */
+#define E32LIBINIT       KU32_C(0x00000004)
+/** Global (set) or per instance (cleared) library termination. */
+#define E32LIBTERM       KU32_C(0x40000000)
+/** Indicates when set in an executable that the process isn't SMP safe. */
+#define E32NOTMPSAFE     KU32_C(0x00080000)
+/** @} */
+
+/** @name Relocations (aka Fixups).
+ * @{ */
+typedef union _offset
+{
+    KU16                offset16;
+    KU32                offset32;
+} offset;
+
+/** A relocation.
+ * @remark this structure isn't very usable since LX relocations comes in too many size variations.
+ */
+struct r32_rlc
+{
+    KU8                 nr_stype;
+    KU8                 nr_flags;
+    KI16                r32_soff;
+    KU16                r32_objmod;
+
+    union targetid
+    {
+        offset          intref;
+        union extfixup
+        {
+            offset      proc;
+            KU32        ord;
+        } extref;
+        struct addfixup
+        {
+            KU16        entry;
+            offset      addval;
+        } addfix;
+    } r32_target;
+    KU16                r32_srccount;
+    KU16                r32_chain;
+};
+
+/** @name Some attempt at size constanstants.
+ * @{
+ */
+#define RINTSIZE16      8
+#define RINTSIZE32      10
+#define RORDSIZE        8
+#define RNAMSIZE16      8
+#define RNAMSIZE32      10
+#define RADDSIZE16      10
+#define RADDSIZE32      12
+/** @} */
+
+/** @name nr_stype (source flags)
+ * @{ */
+#define NRSBYT          0x00
+#define NRSSEG          0x02
+#define NRSPTR          0x03
+#define NRSOFF          0x05
+#define NRPTR48         0x06
+#define NROFF32         0x07
+#define NRSOFF32        0x08
+#define NRSTYP          0x0f
+#define NRSRCMASK       0x0f
+#define NRALIAS         0x10
+#define NRCHAIN         0x20
+/** @} */
+
+/** @name nr_flags (target flags)
+ * @{ */
+#define NRRINT          0x00
+#define NRRORD          0x01
+#define NRRNAM          0x02
+#define NRRENT          0x03
+#define NRRTYP          0x03
+#define NRADD           0x04
+#define NRICHAIN        0x08
+#define NR32BITOFF      0x10
+#define NR32BITADD      0x20
+#define NR16OBJMOD      0x40
+#define NR8BITORD       0x80
+/** @} */
+
+/** @} */
+
+
+/** @name The Object Table (aka segment table)
+ * @{ */
+
+/** The Object Table Entry. */
+struct o32_obj
+{
+    /** The size of the object. */
+    KU32                o32_size;
+    /** The base address of the object. */
+    KU32                o32_base;
+    /** Object flags. */
+    KU32                o32_flags;
+    /** Page map index. */
+    KU32                o32_pagemap;
+    /** Page map size. (doesn't need to be o32_size >> page shift). */
+    KU32                o32_mapsize;
+    /** Reserved */
+    KU32                o32_reserved;
+};
+
+/** @name o32_flags
+ * @{ */
+/** Read access. */
+#define OBJREAD         KU32_C(0x00000001)
+/** Write access. */
+#define OBJWRITE        KU32_C(0x00000002)
+/** Execute access. */
+#define OBJEXEC         KU32_C(0x00000004)
+/** Resource object. */
+#define OBJRSRC         KU32_C(0x00000008)
+/** The object is discarable (i.e. don't swap, just load in pages from the executable).
+ * This overlaps a bit with object type. */
+#define OBJDISCARD      KU32_C(0x00000010)
+/** The object is shared. */
+#define OBJSHARED       KU32_C(0x00000020)
+/** The object has preload pages. */
+#define OBJPRELOAD      KU32_C(0x00000040)
+/** The object has invalid pages. */
+#define OBJINVALID      KU32_C(0x00000080)
+/** Non-permanent, link386 bug. */
+#define LNKNONPERM      KU32_C(0x00000600)
+/** Non-permanent, correct 'value'. */
+#define OBJNONPERM      KU32_C(0x00000000)
+/** Obj Type: The object is permanent and swappable. */
+#define OBJPERM         KU32_C(0x00000100)
+/** Obj Type: The object is permanent and resident (i.e. not swappable). */
+#define OBJRESIDENT     KU32_C(0x00000200)
+/** Obj Type: The object is resident and contigious. */
+#define OBJCONTIG       KU32_C(0x00000300)
+/** Obj Type: The object is permanent and long locable. */
+#define OBJDYNAMIC      KU32_C(0x00000400)
+/** Object type mask. */
+#define OBJTYPEMASK     KU32_C(0x00000700)
+/** x86: The object require an 16:16 alias. */
+#define OBJALIAS16      KU32_C(0x00001000)
+/** x86: Big/Default selector setting, i.e. toggle 32-bit or 16-bit. */
+#define OBJBIGDEF       KU32_C(0x00002000)
+/** x86: conforming selector setting (weird stuff). */
+#define OBJCONFORM      KU32_C(0x00004000)
+/** x86: IOPL. */
+#define OBJIOPL         KU32_C(0x00008000)
+/** @} */
+
+/** A Object Page Map Entry. */
+struct o32_map
+{
+    /** The file offset of the page. */
+    KU32                o32_pagedataoffset;
+    /** The number of bytes of raw page data. */
+    KU16                o32_pagesize;
+    /** Per page flags describing how the page is encoded in the file. */
+    KU16                o32_pageflags;
+};
+
+/** @name o32 o32_pageflags
+ * @{
+ */
+/** Raw page (uncompressed) in the file. */
+#define VALID           KU16_C(0x0000)
+/** RLE encoded page in file. */
+#define ITERDATA        KU16_C(0x0001)
+/** Invalid page, nothing in the file. */
+#define INVALID         KU16_C(0x0002)
+/** Zero page, nothing in file. */
+#define ZEROED          KU16_C(0x0003)
+/** range of pages (what is this?) */
+#define RANGE           KU16_C(0x0004)
+/** Compressed page in file. */
+#define ITERDATA2       KU16_C(0x0005)
+/** @} */
+
+
+/** Iteration Record format (RLE compressed page). */
+struct LX_Iter
+{
+    /** Number of iterations. */
+    KU16                LX_nIter;
+    /** The number of bytes that's being iterated. */
+    KU16                LX_nBytes;
+    /** The bytes. */
+    KU8                 LX_Iterdata;
+};
+
+/** @} */
+
+
+/** A Resource Table Entry */
+struct rsrc32
+{
+    /** Resource Type. */
+    KU16                type;
+    /** Resource ID. */
+    KU16                name;
+    /** Resource size in bytes. */
+    KU32                cb;
+    /** The index of the object containing the resource. */
+    KU16                obj;
+    /** Offset of the resource that within the object. */
+    KU32                offset;
+};
+
+
+/** @name The Entry Table (aka Export Table)
+ * @{ */
+
+/** Entry bundle.
+ * Header descripting up to 255 entries that follows immediatly after this structure. */
+struct b32_bundle
+{
+    /** The number of entries. */
+    KU8                 b32_cnt;
+    /** The type of bundle. */
+    KU8                 b32_type;
+    /** The index of the object containing these entry points. */
+    KU16                b32_obj;
+};
+
+/** @name b32_type
+ * @{ */
+/** Empty bundle, filling up unused ranges of ordinals. */
+#define EMPTY           0x00
+/** 16-bit offset entry point. */
+#define ENTRY16         0x01
+/** 16-bit callgate entry point. */
+#define GATE16          0x02
+/** 32-bit offset entry point. */
+#define ENTRY32         0x03
+/** Forwarder entry point. */
+#define ENTRYFWD        0x04
+/** Typing information present indicator. */
+#define TYPEINFO        0x80
+/** @} */
+
+
+/** Entry point. */
+struct e32_entry
+{
+    /** Entry point flags */
+    KU8                 e32_flags;      /* Entry point flags */
+    union entrykind
+    {
+        /** ENTRY16 or ENTRY32. */
+        offset          e32_offset;
+        /** GATE16 */
+        struct callgate
+        {
+            /** Offset into segment. */
+            KU16        offset;
+            /** The callgate selector */
+            KU16        callgate;
+        } e32_callgate;
+        /** ENTRYFWD */
+        struct fwd
+        {
+            /** Module ordinal number (i.e. into the import module table). */
+            KU16        modord;
+            /** Procedure name or ordinal number. */
+            KU32        value;
+        } e32_fwd;
+    } e32_variant;
+};
+
+/** @name e32_flags
+ * @{ */
+/** Exported entry (set) or private entry (clear). */
+#define E32EXPORT       0x01
+/** Uses shared data. */
+#define E32SHARED       0x02
+/** Parameter word count mask. */
+#define E32PARAMS       0xf8
+/** ENTRYFWD: Imported by ordinal (set) or by name (clear). */
+#define FWD_ORDINAL     0x01
+/** @} */
+
+/** @name dunno
+ * @{ */
+#define FIXENT16        3
+#define FIXENT32        5
+#define GATEENT16       5
+#define FWDENT          7
+/** @} */
+
+#pragma pack()
+
+#endif
+
Index: /trunk/include/k/kLdrFmts/mach-o.h
===================================================================
--- /trunk/include/k/kLdrFmts/mach-o.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/mach-o.h	(revision 2)
@@ -0,0 +1,902 @@
+/* $Id $ */
+/** @file
+ * Mach-0 structures, types and defines.
+ */
+
+#ifndef ___k_kLdrFmts_mach_o_h___
+#define ___k_kLdrFmts_mach_o_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+
+
+/** @defgroup grp_mach_o    The Mach-O Structures, Types, and Defines.
+ * @{
+ */
+
+
+#ifndef IMAGE_FAT_SIGNATURE
+/** The FAT signature (universal binaries). */
+# define IMAGE_FAT_SIGNATURE            KU32_C(0xcafebabe)
+#endif
+#ifndef IMAGE_FAT_SIGNATURE_OE
+/** The FAT signature (universal binaries), other endian. */
+# define IMAGE_FAT_SIGNATURE_OE         KU32_C(0xbebafeca)
+#endif
+
+/**
+ * The fat header found at the start of universal binaries.
+ * It is followed by \a nfat_arch numbers of \a fat_arch structures.
+ */
+typedef struct fat_header
+{
+    KU32            magic;
+    KU32            nfat_arch;
+} fat_header_t;
+
+/**
+ * Description of fat file item.
+ */
+typedef struct fat_arch
+{
+    KI32            cputype;
+    KI32            cpusubtype;
+    KU32            offset;
+    KU32            size;
+    KU32            align;          /**< Power of 2. */
+} fat_arch_t;
+
+
+
+#ifndef IMAGE_MACHO32_SIGNATURE
+/** The 32-bit Mach-O signature. */
+# define IMAGE_MACHO32_SIGNATURE        KU32_C(0xfeedface)
+#endif
+#ifndef IMAGE_MACHO32_SIGNATURE_OE
+/** The 32-bit Mach-O signature, other endian. */
+# define IMAGE_MACHO32_SIGNATURE_OE     KU32_C(0xcefaedfe)
+#endif
+#define MH_MAGIC    IMAGE_MACHO32_SIGNATURE
+#define MH_CIGAM    IMAGE_MACHO32_SIGNATURE_OE
+
+/**
+ * 32-bit Mach-O header.
+ * This is followed by \a ncmds number of load commands.
+ * @see mach_header_64
+ */
+typedef struct mach_header_32
+{
+    KU32            magic;
+    KI32            cputype;
+    KI32            cpusubtype;
+    KU32            filetype;
+    KU32            ncmds;
+    KU32            sizeofcmds;
+    KU32            flags;
+} mach_header_32_t;
+
+
+
+#ifndef IMAGE_MACHO64_SIGNATURE
+/** The 64-bit Mach-O signature. */
+# define IMAGE_MACHO64_SIGNATURE        KU32_C(0xfeedfacf)
+#endif
+#ifndef IMAGE_MACHO64_SIGNATURE_OE
+/** The 64-bit Mach-O signature, other endian. */
+# define IMAGE_MACHO64_SIGNATURE_OE     KU32_C(0xfefaedfe)
+#endif
+#define MH_MAGIC_64 IMAGE_MACHO64_SIGNATURE
+#define MH_CIGAM_64 IMAGE_MACHO64_SIGNATURE_OE
+
+/**
+ * 64-bit Mach-O header.
+ * This is followed by \a ncmds number of load commands.
+ * @see mach_header
+ */
+typedef struct mach_header_64
+{
+    KU32            magic;
+    KI32            cputype;
+    KI32            cpusubtype;
+    KU32            filetype;
+    KU32            ncmds;
+    KU32            sizeofcmds;
+    KU32            flags;
+    KU32            reserved;       /**< (for proper struct and command alignment I guess) */
+} mach_header_64_t;
+
+
+/** @name File types (mach_header_64::filetype, mach_header_32::filetype)
+ * @{
+ */
+#define MH_OBJECT           KU32_C(1) /**< Object (relocatable). */
+#define MH_EXECUTE          KU32_C(2) /**< Executable (demand paged). */
+#define MH_FVMLIB           KU32_C(3) /**< Fixed VM shared library. */
+#define MH_CORE             KU32_C(4) /**< Core file. */
+#define MH_PRELOAD          KU32_C(5) /**< Preloaded executable. */
+#define MH_DYLIB            KU32_C(6) /**< Dynamically bound shared library. */
+#define MH_DYLINKER         KU32_C(7) /**< Dynamic linker. */
+#define MH_BUNDLE           KU32_C(8) /**< Dymamically bound bundle. */
+#define MH_DYLIB_STUB       KU32_C(9) /**< Shared library stub for static linking. */
+#define MH_DSYM             KU32_C(10)/**< Debug symbols. */
+
+/** @} */
+
+
+/** @name Mach-O Header flags (mach_header_64::flags, mach_header_32::flags)
+ * @{
+ */
+#define MH_NOUNDEFS                 KU32_C(0x00000001) /**< No undefined symbols. */
+#define MH_INCRLINK                 KU32_C(0x00000002) /**< Partial increment link output. */
+#define MH_DYLDLINK                 KU32_C(0x00000004) /**< Food for the dynamic linker, not for ld. */
+#define MH_BINDATLOAD               KU32_C(0x00000008) /**< Bind all undefined symbols at load time. */
+#define MH_PREBOUND                 KU32_C(0x00000010) /**< Contains prebound undefined symbols. */
+#define MH_SPLIT_SEGS               KU32_C(0x00000020) /**< Read-only and read-write segments are split. */
+#define MH_LAZY_INIT                KU32_C(0x00000040) /**< Obsolete flag for doing lazy init when data is written. */
+#define MH_TWOLEVEL                 KU32_C(0x00000080) /**< Uses two-level name space bindings. */
+#define MH_FORCE_FLAT               KU32_C(0x00000100) /**< Task: The executable forces all images to use flat name space bindings. */
+#define MH_NOMULTIDEFS              KU32_C(0x00000200) /**< No multiple symbol definitions, safe to use two-level namespace hints. */
+#define MH_NOFIXPREBINDING          KU32_C(0x00000400) /**< The dynamic linker should not notify the prebinding agent about this executable. */
+#define MH_PREBINDABLE              KU32_C(0x00000800) /**< Not prebound, but it can be. Invalid if MH_PREBOUND is set. */
+#define MH_ALLMODSBOUND             KU32_C(0x00001000) /**< Binds to all two-level namespace modules of preqs. Requires MH_PREBINDABLE and MH_TWOLEVEL to be set. */
+#define MH_SUBSECTIONS_VIA_SYMBOLS  KU32_C(0x00002000) /**< Safe to divide sections into sub-sections via symbols for dead code stripping. */
+#define MH_CANONICAL                KU32_C(0x00004000) /**< Canonicalized via unprebind. */
+#define MH_WEAK_DEFINES             KU32_C(0x00008000) /**< The (finally) linked image has weak symbols. */
+#define MH_BINDS_TO_WEAK            KU32_C(0x00010000) /**< The (finally) linked image uses weak symbols. */
+#define MH_ALLOW_STACK_EXECUTION    KU32_C(0x00020000) /**< Task: allow stack execution. (MH_EXECUTE only) */
+#define MH_VALID_FLAGS              KU32_C(0x0003ffff) /**< Mask containing the defined flags. */
+/** @} */
+
+
+/** @name CPU types / bits (mach_header_64::cputype, mach_header_32::cputype, fat_arch::cputype)
+ * @{
+ */
+#define CPU_ARCH_MASK               KI32_C(0xff000000)
+#define CPU_ARCH_ABI64              KI32_C(0x01000000)
+#define CPU_TYPE_ANY                KI32_C(-1)
+#define CPU_TYPE_VAX                KI32_C(1)
+#define CPU_TYPE_MC680x0            KI32_C(6)
+#define CPU_TYPE_X86                KI32_C(7)
+#define CPU_TYPE_I386               CPU_TYPE_X86
+#define CPU_TYPE_X86_64             (CPU_TYPE_X86 | CPU_ARCH_ABI64)
+#define CPU_TYPE_MC98000            KI32_C(10)
+#define CPU_TYPE_HPPA               KI32_C(11)
+#define CPU_TYPE_MC88000            KI32_C(13)
+#define CPU_TYPE_SPARC              KI32_C(14)
+#define CPU_TYPE_I860               KI32_C(15)
+#define CPU_TYPE_POWERPC            KI32_C(18)
+#define CPU_TYPE_POWERPC64          (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
+/** @} */
+
+
+/** @name CPU subtypes (mach_header_64::cpusubtype, mach_header_32::cpusubtype, fat_arch::cpusubtype)
+ * @{ */
+#define CPU_SUBTYPE_MULTIPLE        KI32_C(-1)
+#define CPU_SUBTYPE_LITTLE_ENDIAN   KI32_C(0)  /**< figure this one out. */
+#define CPU_SUBTYPE_BIG_ENDIAN      KI32_C(1)  /**< ditto */
+
+/* VAX */
+#define CPU_SUBTYPE_VAX_ALL         KI32_C(0)
+#define CPU_SUBTYPE_VAX780          KI32_C(1)
+#define CPU_SUBTYPE_VAX785          KI32_C(2)
+#define CPU_SUBTYPE_VAX750          KI32_C(3)
+#define CPU_SUBTYPE_VAX730          KI32_C(4)
+#define CPU_SUBTYPE_UVAXI           KI32_C(5)
+#define CPU_SUBTYPE_UVAXII          KI32_C(6)
+#define CPU_SUBTYPE_VAX8200         KI32_C(7)
+#define CPU_SUBTYPE_VAX8500         KI32_C(8)
+#define CPU_SUBTYPE_VAX8600         KI32_C(9)
+#define CPU_SUBTYPE_VAX8650         KI32_C(10)
+#define CPU_SUBTYPE_VAX8800         KI32_C(11)
+#define CPU_SUBTYPE_UVAXIII         KI32_C(12)
+
+/* MC680xx */
+#define CPU_SUBTYPE_MC680x0_ALL     KI32_C(1)
+#define CPU_SUBTYPE_MC68030         KI32_C(1)
+#define CPU_SUBTYPE_MC68040         KI32_C(2)
+#define CPU_SUBTYPE_MC68030_ONLY    KI32_C(3)
+
+/* I386 */
+#define CPU_SUBTYPE_INTEL(fam, model)       ( (KI32)(((model) << 4) | (fam)) )
+#define CPU_SUBTYPE_INTEL_FAMILY(subtype)   ( (subtype) & 0xf )
+#define CPU_SUBTYPE_INTEL_MODEL(subtype)    ( (subtype) >> 4 )
+#define CPU_SUBTYPE_INTEL_FAMILY_MAX        0xf
+#define CPU_SUBTYPE_INTEL_MODEL_ALL         0
+
+#define CPU_SUBTYPE_I386_ALL        CPU_SUBTYPE_INTEL(3, 0)
+#define CPU_SUBTYPE_386             CPU_SUBTYPE_INTEL(3, 0)
+#define CPU_SUBTYPE_486             CPU_SUBTYPE_INTEL(4, 0)
+#define CPU_SUBTYPE_486SX           CPU_SUBTYPE_INTEL(4, 8)
+#define CPU_SUBTYPE_586             CPU_SUBTYPE_INTEL(5, 0)
+#define CPU_SUBTYPE_PENT            CPU_SUBTYPE_INTEL(5, 0)
+#define CPU_SUBTYPE_PENTPRO         CPU_SUBTYPE_INTEL(6, 1)
+#define CPU_SUBTYPE_PENTII_M3       CPU_SUBTYPE_INTEL(6, 3)
+#define CPU_SUBTYPE_PENTII_M5       CPU_SUBTYPE_INTEL(6, 5)
+#define CPU_SUBTYPE_CELERON         CPU_SUBTYPE_INTEL(7, 6)
+#define CPU_SUBTYPE_CELERON_MOBILE  CPU_SUBTYPE_INTEL(7, 7)
+#define CPU_SUBTYPE_PENTIUM_3       CPU_SUBTYPE_INTEL(8, 0)
+#define CPU_SUBTYPE_PENTIUM_3_M     CPU_SUBTYPE_INTEL(8, 1)
+#define CPU_SUBTYPE_PENTIUM_3_XEON  CPU_SUBTYPE_INTEL(8, 2)
+#define CPU_SUBTYPE_PENTIUM_M       CPU_SUBTYPE_INTEL(9, 0)
+#define CPU_SUBTYPE_PENTIUM_4       CPU_SUBTYPE_INTEL(10, 0)
+#define CPU_SUBTYPE_PENTIUM_4_M     CPU_SUBTYPE_INTEL(10, 1)
+#define CPU_SUBTYPE_ITANIUM         CPU_SUBTYPE_INTEL(11, 0)
+#define CPU_SUBTYPE_ITANIUM_2       CPU_SUBTYPE_INTEL(11, 1)
+#define CPU_SUBTYPE_XEON            CPU_SUBTYPE_INTEL(12, 0)
+#define CPU_SUBTYPE_XEON_MP         CPU_SUBTYPE_INTEL(12, 1)
+
+/* X86 */
+#define CPU_SUBTYPE_X86_ALL         KI32_C(3) /* CPU_SUBTYPE_I386_ALL */
+#define CPU_SUBTYPE_X86_64_ALL      KI32_C(3) /* CPU_SUBTYPE_I386_ALL */
+#define CPU_SUBTYPE_X86_ARCH1       KI32_C(4) /* CPU_SUBTYPE_I486_ALL */
+
+/* MIPS */
+#define CPU_SUBTYPE_MIPS_ALL        KI32_C(0)
+#define CPU_SUBTYPE_MIPS_R2300      KI32_C(1)
+#define CPU_SUBTYPE_MIPS_R2600      KI32_C(2)
+#define CPU_SUBTYPE_MIPS_R2800      KI32_C(3)
+#define CPU_SUBTYPE_MIPS_R2000a     KI32_C(4)
+#define CPU_SUBTYPE_MIPS_R2000      KI32_C(5)
+#define CPU_SUBTYPE_MIPS_R3000a     KI32_C(6)
+#define CPU_SUBTYPE_MIPS_R3000      KI32_C(7)
+
+/* MC98000 (PowerPC) */
+#define CPU_SUBTYPE_MC98000_ALL     KI32_C(0)
+#define CPU_SUBTYPE_MC98601         KI32_C(1)
+
+/* HP-PA */
+#define CPU_SUBTYPE_HPPA_ALL        KI32_C(0)
+#define CPU_SUBTYPE_HPPA_7100       KI32_C(0)
+#define CPU_SUBTYPE_HPPA_7100LC     KI32_C(1)
+
+/* MC88000 */
+#define CPU_SUBTYPE_MC88000_ALL     KI32_C(0)
+#define CPU_SUBTYPE_MC88100         KI32_C(1)
+#define CPU_SUBTYPE_MC88110         KI32_C(2)
+
+/* SPARC */
+#define CPU_SUBTYPE_SPARC_ALL       KI32_C(0)
+
+/* I860 */
+#define CPU_SUBTYPE_I860_ALL        KI32_C(0)
+#define CPU_SUBTYPE_I860_860        KI32_C(1)
+
+/* PowerPC */
+#define CPU_SUBTYPE_POWERPC_ALL     KI32_C(0)
+#define CPU_SUBTYPE_POWERPC_601     KI32_C(1)
+#define CPU_SUBTYPE_POWERPC_602     KI32_C(2)
+#define CPU_SUBTYPE_POWERPC_603     KI32_C(3)
+#define CPU_SUBTYPE_POWERPC_603e    KI32_C(4)
+#define CPU_SUBTYPE_POWERPC_603ev   KI32_C(5)
+#define CPU_SUBTYPE_POWERPC_604     KI32_C(6)
+#define CPU_SUBTYPE_POWERPC_604e    KI32_C(7)
+#define CPU_SUBTYPE_POWERPC_620     KI32_C(8)
+#define CPU_SUBTYPE_POWERPC_750     KI32_C(9)
+#define CPU_SUBTYPE_POWERPC_7400    KI32_C(10)
+#define CPU_SUBTYPE_POWERPC_7450    KI32_C(11)
+#define CPU_SUBTYPE_POWERPC_Max     KI32_C(10)
+#define CPU_SUBTYPE_POWERPC_SCVger  KI32_C(11)
+#define CPU_SUBTYPE_POWERPC_970     KI32_C(100)
+
+/** @} */
+
+
+
+/** @defgroup grp_macho_o_lc        Load Commands
+ * @{ */
+
+/**
+ * The load command common core structure.
+ *
+ * After the Mach-O header follows an array of variable sized
+ * load command which all has this header in common.
+ */
+typedef struct load_command
+{
+    KU32            cmd;            /**< The load command id. */
+    KU32            cmdsize;        /**< The size of the command (including this header). */
+} load_command_t;
+
+/** @name Load Command IDs (load_command::cmd)
+ * @{
+ */
+/** Flag that when set requires the dynamic linker to fail if it doesn't
+ * grok the command. The dynamic linker will otherwise ignore commands it
+ * doesn't understand. Introduced with Mac OS X 10.1. */
+#define LC_REQ_DYLD         KU32_C(0x80000000)
+
+#define LC_SEGMENT_32       KU32_C(0x01)  /**< Segment to be mapped (32-bit). See segment_command_32. */
+#define LC_SYMTAB           KU32_C(0x02)  /**< 'stab' symbol table. See symtab_command. */
+#define LC_SYMSEG           KU32_C(0x03)  /**< Obsoleted gdb symbol table. */
+#define LC_THREAD           KU32_C(0x04)  /**< Thread. See thread_command. */
+#define LC_UNIXTHREAD       KU32_C(0x05)  /**< Unix thread (includes stack and stuff). See thread_command. */
+#define LC_LOADFVMLIB       KU32_C(0x06)  /**< Load a specified fixed VM shared library  (obsolete?). See fvmlib_command. */
+#define LC_IDFVMLIB         KU32_C(0x07)  /**< Fixed VM shared library id (obsolete?). See fvmlib_command. */
+#define LC_IDENT            KU32_C(0x08)  /**< Identification info (obsolete). See ident_command. */
+#define LC_FVMFILE          KU32_C(0x09)  /**< Fixed VM file inclusion (internal). See fvmfile_command. */
+#define LC_PREPAGE          KU32_C(0x0a)  /**< Prepage command (internal). See ?? */
+#define LC_DYSYMTAB         KU32_C(0x0b)  /**< Symbol table for dynamic linking. See dysymtab_command. */
+#define LC_LOAD_DYLIB       KU32_C(0x0c)  /**< Load a dynamically linked shared library. See dylib_command. */
+#define LC_ID_DYLIB         KU32_C(0x0d)  /**< Dynamically linked share library ident. See dylib_command. */
+#define LC_LOAD_DYLINKER    KU32_C(0x0e)  /**< Load a dynamical link editor. See dylinker_command. */
+#define LC_ID_DYLINKER      KU32_C(0x0f)  /**< Dynamic link editor ident. See dylinker_command. */
+#define LC_PREBOUND_DYLIB   KU32_C(0x10)  /**< Prebound modules for dynamically linking of a shared lib. See prebound_dylib_command. */
+#define LC_ROUTINES         KU32_C(0x11)  /**< Image routines. See routines_command_32. */
+#define LC_SUB_FRAMEWORK    KU32_C(0x12)  /**< Sub framework. See sub_framework_command. */
+#define LC_SUB_UMBRELLA     KU32_C(0x13)  /**< Sub umbrella. See sub_umbrella_command. */
+#define LC_SUB_CLIENT       KU32_C(0x14)  /**< Sub client. See sub_client_command. */
+#define LC_SUB_LIBRARY      KU32_C(0x15)  /**< Sub library. See sub_library_command. */
+#define LC_TWOLEVEL_HINTS   KU32_C(0x16)  /**< Two-level namespace lookup hints. See twolevel_hints_command. */
+#define LC_PREBIND_CKSUM    KU32_C(0x17)  /**< Prebind checksum. See prebind_cksum_command. */
+#define LC_LOAD_WEAK_DYLIB (KU32_C(0x18) | LC_REQ_DYLD) /**< Dylib that can be missing, all symbols weak. See dylib_command. */
+#define LC_SEGMENT_64       KU32_C(0x19)  /**< segment to be mapped (64-bit). See segment_command_32. */
+#define LC_ROUTINES_64      KU32_C(0x1a)  /**< Image routines (64-bit). See routines_command_32. */
+#define LC_UUID             KU32_C(0x1b)  /**< The UUID of the object module. See uuid_command.  */
+/** @} */
+
+
+/**
+ * Load Command String.
+ */
+typedef struct lc_str
+{
+    /** Offset of the string relative to the load_command structure.
+     * The string is zero-terminated. the size of the load command
+     * is zero padded up to a multiple of 4 bytes. */
+    KU32            offset;
+} lc_str_t;
+
+
+/**
+ * Segment load command (32-bit).
+ */
+typedef struct segment_command_32
+{
+    KU32            cmd;            /**< LC_SEGMENT */
+    KU32            cmdsize;        /**< sizeof(self) + sections. */
+    char            segname[16];    /**< The segment name. */
+    KU32            vmaddr;         /**< Memory address of this segment. */
+    KU32            vmsize;         /**< Size of this segment. */
+    KU32            fileoff;        /**< The file location of the segment. */
+    KU32            filesize;       /**< The file size of the segment. */
+    KU32            maxprot;        /**< Maximum VM protection. */
+    KU32            initprot;       /**< Initial VM protection. */
+    KU32            nsects;         /**< Number of section desciptors following this structure. */
+    KU32            flags;          /**< Flags (SG_*). */
+} segment_command_32_t;
+
+
+/**
+ * Segment load command (64-bit).
+ * Same as segment_command_32 except 4 members has been blown up to 64-bit.
+ */
+typedef struct segment_command_64
+{
+    KU32            cmd;            /**< LC_SEGMENT */
+    KU32            cmdsize;        /**< sizeof(self) + sections. */
+    char            segname[16];    /**< The segment name. */
+    KU64            vmaddr;         /**< Memory address of this segment. */
+    KU64            vmsize;         /**< Size of this segment. */
+    KU64            fileoff;        /**< The file location of the segment. */
+    KU64            filesize;       /**< The file size of the segment. */
+    KU32            maxprot;        /**< Maximum VM protection. */
+    KU32            initprot;       /**< Initial VM protection. */
+    KU32            nsects;         /**< Number of section desciptors following this structure. */
+    KU32            flags;          /**< Flags (SG_*). */
+} segment_command_64_t;
+
+/** @name Segment flags (segment_command_64::flags, segment_command_32::flags)
+ * @{ */
+/** Map the file bits in the top end of the memory area for the segment
+ * instead of the low end. Intended for stacks in core dumps.
+ * The part of the segment memory not covered by file bits will be zeroed. */
+#define SG_HIGHVM           KU32_C(0x00000001)
+/** This segment is the virtual memory allocated by a fixed VM library.
+ * (Used for overlap checking in the linker.) */
+#define SG_FVMLIB           KU32_C(0x00000002)
+/** No relocations for or symbols that's relocated to in this segment.
+ * The segment can therefore safely be replaced. */
+#define SG_NORELOC          KU32_C(0x00000004)
+/** The segment is protected.
+ * The first page isn't protected if it starts at file offset 0
+ * (so that the mach header and this load command can be easily mapped). */
+#define SG_PROTECTED_VERSION_1 KU32_C(0x00000008)
+/** @} */
+
+
+/**
+ * 32-bit section (part of a segment load command).
+ */
+typedef struct section_32
+{
+    char            sectname[16];   /**< The section name. */
+    char            segname[16];    /**< The name of the segment this section goes into. */
+    KU32            addr;           /**< The memory address of this section. */
+    KU32            size;           /**< The size of this section. */
+    KU32            offset;         /**< The file offset of this section. */
+    KU32            align;          /**< The section alignment (**2). */
+    KU32            reloff;         /**< The file offset of the relocations. */
+    KU32            nreloc;         /**< The number of relocations. */
+    KU32            flags;          /**< The section flags; section type and attribs */
+    KU32            reserved1;      /**< Reserved / offset / index. */
+    KU32            reserved2;      /**< Reserved / count / sizeof. */
+} section_32_t;
+
+/**
+ * 64-bit section (part of a segment load command).
+ */
+typedef struct section_64
+{
+    char            sectname[16];   /**< The section name. */
+    char            segname[16];    /**< The name of the segment this section goes into. */
+    KU64            addr;           /**< The memory address of this section. */
+    KU64            size;           /**< The size of this section. */
+    KU32            offset;         /**< The file offset of this section. */
+    KU32            align;          /**< The section alignment (**2). */
+    KU32            reloff;         /**< The file offset of the relocations. */
+    KU32            nreloc;         /**< The number of relocations. */
+    KU32            flags;          /**< The section flags; section type and attribs */
+    KU32            reserved1;      /**< Reserved / offset / index. */
+    KU32            reserved2;      /**< Reserved / count / sizeof. */
+    KU32            reserved3;      /**< (Just) Reserved. */
+} section_64_t;
+
+/** @name Section flags (section_64::flags, section_32::flags)
+ * @{
+ */
+/** Section type mask. */
+#define SECTION_TYPE                KU32_C(0x000000ff)
+/** Regular section. */
+#define S_REGULAR                   0x0
+/** Zero filled section. */
+#define S_ZEROFILL                  0x1
+/** C literals. */
+#define S_CSTRING_LITERALS          0x2
+/** 4 byte literals. */
+#define S_4BYTE_LITERALS            0x3
+/** 8 byte literals. */
+#define S_8BYTE_LITERALS            0x4
+/** Pointer to literals. */
+#define S_LITERAL_POINTERS          0x5
+/** Section containing non-lazy symbol pointers.
+ * Reserved1 == start index in the indirect symbol table. */
+#define S_NON_LAZY_SYMBOL_POINTERS  0x6
+/** Section containing lazy symbol pointers.
+ * Reserved1 == start index in the indirect symbol table. */
+#define S_LAZY_SYMBOL_POINTERS      0x7
+/** Section containing symbol stubs.
+ * Reserved2 == stub size. */
+#define S_SYMBOL_STUBS              0x8
+/** Section containing function pointers for module initialization. . */
+#define S_MOD_INIT_FUNC_POINTERS    0x9
+/** Section containing function pointers for module termination. . */
+#define S_MOD_TERM_FUNC_POINTERS    0xa
+/** Section containing symbols that are to be coalesced. */
+#define S_COALESCED                 0xb
+/** Zero filled section that be larger than 4GB. */
+#define S_GB_ZEROFILL               0xc
+/** Section containing pairs of function pointers for interposing. */
+#define S_INTERPOSING               0xd
+/** 16 byte literals. */
+#define S_16BYTE_LITERALS           0xe
+
+/** Section attribute mask. */
+#define SECTION_ATTRIBUTES          KU32_C(0xffffff00)
+
+/** User settable attribute mask. */
+#define SECTION_ATTRIBUTES_USR      KU32_C(0xff000000)
+/** Pure instruction (code). */
+#define S_ATTR_PURE_INSTRUCTIONS    KU32_C(0x80000000)
+/** ranlib, ignore my symbols... */
+#define S_ATTR_NO_TOC               KU32_C(0x40000000)
+/** May strip static symbols when linking int a MH_DYLDLINK file. */
+#define S_ATTR_STRIP_STATIC_SYMS    KU32_C(0x20000000)
+/** No dead stripping. */
+#define S_ATTR_NO_DEAD_STRIP        KU32_C(0x10000000)
+/** Live support. */
+#define S_ATTR_LIVE_SUPPORT         KU32_C(0x08000000)
+/** Contains self modifying code (generally i386 code stub for dyld). */
+#define S_ATTR_SELF_MODIFYING_CODE  KU32_C(0x04000000)
+/** Debug info (DWARF usually). */
+#define S_ATTR_DEBUG                KU32_C(0x02000000)
+
+/** System settable attribute mask. */
+#define SECTION_ATTRIBUTES_SYS      KU32_C(0x00ffff00)
+/** Contains some instructions (code). */
+#define S_ATTR_SOME_INSTRUCTIONS    KU32_C(0x00000400)
+/** Has external relocations. */
+#define S_ATTR_EXT_RELOC            KU32_C(0x00000200)
+/** Has internal (local) relocations. */
+#define S_ATTR_LOC_RELOC            KU32_C(0x00000100)
+/** @} */
+
+/** @name Known Segment and Section Names.
+ * Some of these implies special linker behaviour.
+ * @{
+ */
+/** Page zero - not-present page for catching invalid access. (MH_EXECUTE typically) */
+#define SEG_PAGEZERO        "__PAGEZERO"
+/** Traditional UNIX text segment.
+ * Defaults to R-X. */
+#define SEG_TEXT            "__TEXT"
+/** The text part of SEG_TEXT. */
+#define SECT_TEXT               "__text"
+/** The fvmlib initialization. */
+#define SECT_FVMLIB_INIT0       "__fvmlib_init0"
+/** The section following the fvmlib initialization. */
+#define SECT_FVMLIB_INIT1       "__fvmlib_init1"
+/** The traditional UNIX data segment. (DGROUP to DOS and OS/2 people.) */
+#define SEG_DATA            "__DATA"
+/** The initialized data section. */
+#define SECT_DATA               "__data"
+/** The uninitialized data section. */
+#define SECT_BSS                "__bss"
+/** The common symbol section. */
+#define SECT_COMMON             "__common"
+/** Objective-C runtime segment. */
+#define SEG_OBJC            "__OBJC"
+/** Objective-C symbol table section. */
+#define SECT_OBJC_SYMBOLS       "__symbol_table"
+/** Objective-C module information section. */
+#define SECT_OBJC_MODULES       "__module_info"
+/** Objective-C string table section. */
+#define SECT_OBJC_STRINGS       "__selector_strs"
+/** Objective-C string table section. */
+#define SECT_OBJC_REFS          "__selector_refs"
+/** Icon segment. */
+#define SEG_ICON            "__ICON"
+/** The icon headers. */
+#define SECT_ICON_HEADER        "__header"
+/** The icons in the TIFF format. */
+#define SECT_ICON_TIFF          "__tiff"
+/** ld -seglinkedit segment containing all the structs create and maintained
+ * by the linker. MH_EXECUTE and MH_FVMLIB only. */
+#define SEG_LINKEDIT        "__LINKEDIT"
+/** The unix stack segment. */
+#define SEG_UNIXSTACK       "__UNIXSTACK"
+/** The segment for the self modifying code for dynamic linking.
+ * Implies RWX permissions. */
+#define SEG_IMPORT          "__IMPORT"
+/** @} */
+
+
+/** @todo fvmlib */
+/** @todo fvmlib_command (LC_IDFVMLIB or LC_LOADFVMLIB) */
+/** @todo dylib */
+/** @todo dylib_command (LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB) */
+/** @todo sub_framework_command (LC_SUB_FRAMEWORK) */
+/** @todo sub_client_command (LC_SUB_CLIENT) */
+/** @todo sub_umbrella_command (LC_SUB_UMBRELLA) */
+/** @todo sub_library_command (LC_SUB_LIBRARY) */
+/** @todo prebound_dylib_command (LC_PREBOUND_DYLIB) */
+/** @todo dylinker_command (LC_ID_DYLINKER or LC_LOAD_DYLINKER) */
+
+
+/**
+ * Thread command.
+ *
+ * State description of a thread that is to be created. The description
+ * is made up of a number of state structures preceded by a 32-bit flavor
+ * and 32-bit count field stating the kind of stat structure and it's size
+ * in KU32 items respecitvly.
+ *
+ * LC_UNIXTHREAD differs from LC_THREAD in that it implies stack creation
+ * and that it's started with the typical main(int, char **, char **) frame
+ * on the stack.
+ */
+typedef struct thread_command
+{
+    KU32            cmd;        /**< LC_UNIXTHREAD or LC_THREAD. */
+    KU32            cmdsize;    /**< The size of the command (including this header). */
+} thread_command_t;
+
+
+/** @todo routines_command (LC_ROUTINES) */
+/** @todo routines_command_64 (LC_ROUTINES_64) */
+
+
+/**
+ * Symbol table command.
+ * Contains a.out style symbol table with some tricks.
+ */
+typedef struct symtab_command
+{
+    KU32            cmd;        /**< LC_SYMTAB */
+    KU32            cmdsize;    /** sizeof(symtab_command_t) */
+    KU32            symoff;     /** The file offset of the symbol table. */
+    KU32            nsyms;      /** The number of symbols in the symbol table. */
+    KU32            stroff;     /** The file offset of the string table. */
+    KU32            strsize;    /** The size of the string table. */
+} symtab_command_t;
+
+
+/** @todo dysymtab_command (LC_DYSYMTAB)  */
+/** @todo dylib_table_of_contents */
+/** @todo dylib_module_32 */
+/** @todo dylib_module_64 */
+/** @todo dylib_reference */
+/** @todo twolevel_hints_command (LC_TWOLEVEL_HINTS) */
+/** @todo twolevel_hint */
+/** @todo prebind_cksum_command (LC_PREBIND_CKSUM) */
+
+
+/**
+ * UUID generated by ld.
+ */
+typedef struct uuid_command
+{
+    KU32            cmd;        /**< LC_UUID */
+    KU32            cmdsize;    /**< sizeof(uuid_command_t) */
+    KU8             uuid[16];   /** The UUID bytes. */
+} uuid_command_t;
+
+
+/** @todo symseg_command (LC_SYMSEG) */
+/** @todo ident_command (LC_IDENT) */
+/** @todo fvmfile_command (LC_FVMFILE) */
+
+/** @} */
+
+
+
+/** @defgroup grp_macho_o_syms  Symbol Table
+ * @{ */
+
+/**
+ * The 32-bit Mach-O version of the nlist structure.
+ *
+ * This differs from the a.out nlist struct in that the unused n_other field
+ * was renamed to n_sect and used for keeping the relevant section number.
+ * @remark  This structure is not name mach_nlist_32 in the Apple headers, but nlist.
+ */
+typedef struct macho_nlist_32
+{
+    union
+    {
+        KI32    n_strx;         /**< Offset (index) into the string table. 0 means "". */
+    }           n_un;
+    KU8         n_type;         /**< Symbol type. */
+    KU8         n_sect;         /**< Section number of NO_SECT. */
+    KI16        n_desc;         /**< Type specific, debug info details mostly.*/
+    KU32        n_value;        /**< The symbol value or stab offset. */
+} macho_nlist_32_t;
+
+
+/**
+ * The 64-bit Mach-O version of the nlist structure.
+ * @see macho_nlist_32
+ */
+typedef struct macho_nlist_64
+{
+    union
+    {
+        KU32    n_strx;         /**< Offset (index) into the string table. 0 means "". */
+    }           n_un;
+    KU8         n_type;         /**< Symbol type. */
+    KU8         n_sect;         /**< Section number of NO_SECT. */
+    KI16        n_desc;         /**< Type specific, debug info details mostly.*/
+    KU64        n_value;        /**< The symbol value or stab offset. */
+} macho_nlist_64_t;
+
+
+/** @name Symbol Type Constants (macho_nlist_32_t::n_type, macho_nlist_64_t::n_type)
+ *
+ * In the Mach-O world n_type is somewhat similar to a.out, meaning N_EXT, N_UNDF, N_ABS
+ * and the debug symbols are essentially the same, but the remaining stuff is different.
+ * The main reason for this is that the encoding of section has been moved to n_sect
+ * to permit up to 255 sections instead of the fixed 3 a.out sections (not counting
+ * the abs symbols and set vectors).
+ *
+ * To avoid confusion with a.out the Mach-O constants has been fitted with a MACHO_
+ * prefix here.
+ *
+ * Common symbols (aka communal symbols and comdefs) are represented by
+ * n_type = MACHO_N_EXT | MACHO_N_UNDF, n_sect = NO_SECT and n_value giving
+ * the size.
+ *
+ *
+ * Symbol table entries can be inserted directly in the assembly code using
+ * this notation:
+ * @code
+ *      .stabs "n_name", n_type, n_sect, n_desc, n_value
+ * @endcode
+ *
+ * (1) The line number is optional, GCC doesn't set it.
+ * (2) The type is optional, GCC doesn't set it.
+ * (3) The binutil header is "skeptical" about the line. I'm skeptical about the whole thing... :-)
+ * (M) Mach-O specific?
+ * (S) Sun specific?
+ * @{
+ */
+
+/* Base masks. */
+#define MACHO_N_EXT     KU8_C(0x01)   /**< External symbol (when set) (N_EXT). */
+#define MACHO_N_TYPE    KU8_C(0x0e)   /**< Symbol type (N_TYPE without the 8th bit). */
+#define MACHO_N_PEXT    KU8_C(0x10)   /**< Private extern symbol (when set). (M) */
+#define MACHO_N_STAB    KU8_C(0xe0)   /**< Debug symbol mask (N_STAB). */
+
+/* MACHO_N_TYPE values. */
+#define MACHO_N_UNDF    KU8_C(0x00)   /**< MACHO_N_TYPE: Undefined symbol (N_UNDF). n_sect = NO_SECT. */
+#define MACHO_N_ABS     KU8_C(0x02)   /**< MACHO_N_TYPE: Absolute symbol (N_UNDF). n_sect = NO_SECT. */
+#define MACHO_N_INDR    KU8_C(0x0a)   /**< MACHO_N_TYPE: Indirect symbol, n_value is the index of the symbol. (M) */
+#define MACHO_N_PBUD    KU8_C(0x0c)   /**< MACHO_N_TYPE: Prebound undefined symbo (defined in a dylib). (M) */
+#define MACHO_N_SECT    KU8_C(0x0e)   /**< MACHO_N_TYPE: Defined in the section given by n_sects. (M) */
+
+/* Debug symbols. */
+#define MACHO_N_GSYM    KU8_C(0x20)   /**< Global variable.       "name",, NO_SECT, type, 0       (2) */
+#define MACHO_N_FNAME   KU8_C(0x22)   /**< Function name (F77).   "name",, NO_SECT, 0, 0 */
+#define MACHO_N_FUN     KU8_C(0x24)   /**< Function / text var.   "name",, section, line, address (1) */
+#define MACHO_N_STSYM   KU8_C(0x26)   /**< Static data symbol.    "name",, section, type, address (2) */
+#define MACHO_N_LCSYM   KU8_C(0x28)   /**< static bss symbol.     "name",, section, type, address (2) */
+    /* omits N_MAIN and N_ROSYM. */
+#define MACHO_N_BNSYM   KU8_C(0x2e)   /**< Begin nsect symbol.         0,, section, 0, address (M) */
+#define MACHO_N_PC      KU8_C(0x30)   /**< Global pascal symbol.  "name",, NO_SECT, subtype?, line (3) */
+    /* omits N_NSYMS, N_NOMAP and N_OBJ. */
+#define MACHO_N_OPT     KU8_C(0x3c)   /**< Options for the debugger related to the language of the
+                                             source file.           "options?",,,, */
+#define MACHO_N_RSYM    KU8_C(0x40)   /**< Register variable.     "name",, NO_SECT, type, register */
+    /* omits N_M2C */
+#define MACHO_N_SLINE   KU8_C(0x44)   /**< Source line.                0,, section, line, address */
+    /* omits N_DSLINE, N_BSLINE / N_BROWS, N_DEFD and N_FLINE. */
+#define MACHO_N_ENSYM   KU8_C(0x4e)   /**< End nsect symbol.           0,, section, 0, address (M) */
+    /* omits N_EHDECL / N_MOD2 and N_CATCH. */
+#define MACHO_N_SSYM    KU8_C(0x60)   /**< Struct/union element.  "name",, NO_SECT, type, offset */
+    /* omits N_ENDM */
+#define MACHO_N_SO      KU8_C(0x64)   /**< Source file name.      "fname",, section, 0, address */
+#define MACHO_N_OSO     KU8_C(0x66)   /**< Object file name.      "fname",, 0, 0, st_mtime (M?) */
+    /* omits N_ALIAS */
+#define MACHO_N_LSYM    KU8_C(0x80)   /**< Stack variable.        "name",, NO_SECT, type, frame_offset */
+#define MACHO_N_BINCL   KU8_C(0x82)   /**< Begin #include.        "fname",, NO_SECT, 0, sum? */
+#define MACHO_N_SOL     KU8_C(0x84)   /**< #included file.        "fname",, section, 0, start_address (S) */
+#define MACHO_N_PARAMS  KU8_C(0x86)   /**< Compiler params.       "params",, NO_SECT, 0, 0 */
+#define MACHO_N_VERSION KU8_C(0x88)   /**< Compiler version.      "version",, NO_SECT, 0, 0 */
+#define MACHO_N_OLEVEL  KU8_C(0x8A)   /**< Compiler -O level.     "level",, NO_SECT, 0, 0 */
+#define MACHO_N_PSYM    KU8_C(0xa0)   /**< Parameter variable.    "name",, NO_SECT, type, frame_offset */
+#define MACHO_N_EINCL   KU8_C(0xa2)   /**< End #include.          "fname",, NO_SECT, 0, 0 (S) */
+#define MACHO_N_ENTRY   KU8_C(0xa4)   /**< Alternate entry point. "name",, section, line, address */
+#define MACHO_N_LBRAC   KU8_C(0xc0)   /**< Left bracket.               0,, NO_SECT, nesting_level, address */
+#define MACHO_N_EXCL    KU8_C(0xc2)   /**< Deleted include file.  "fname",, NO_SECT, 0, sum?  (S) */
+    /* omits N_SCOPE */
+#define MACHO_N_RBRAC   KU8_C(0xe0)   /**< Right bracket.              0,, NO_SECT, nesting_level, address */
+#define MACHO_N_BCOMM   KU8_C(0xe2)   /**< Begin common.          "name",, NO_SECT?, 0, 0 */
+#define MACHO_N_ECOMM   KU8_C(0xe4)   /**< End common.            "name",, section, 0, 0 */
+#define MACHO_N_ECOML   KU8_C(0xe8)   /**< End local common.           0,, section, 0, address */
+#define MACHO_N_LENG    KU8_C(0xfe)   /**< Length-value of the preceding entry.
+                                                                    "name",, NO_SECT, 0, length */
+
+/** @} */
+
+/** @name Symbol Description Bits (macho_nlist_32_t::n_desc, macho_nlist_64_t::n_desc)
+ *
+ * Mach-O puts the n_desc field to a number of uses, like lazy binding , library
+ * ordinal numbers for -twolevel_namespace, stripping and weak symbol handling.
+ *
+ * @remark The REFERENCE_FLAGS_* are really not flags in the normal sense (bit),
+ *         they are more like enum values.
+ * @{
+ */
+
+#define REFERENCE_TYPE                  KU16_C(0x000f)    /**< The reference type mask. */
+#define REFERENCE_FLAG_UNDEFINED_NON_LAZY             0     /**< Normal undefined symbol. */
+#define REFERENCE_FLAG_UNDEFINED_LAZY                 1     /**< Lazy undefined symbol. */
+#define REFERENCE_FLAG_DEFINED                        2     /**< Defined symbol (dynamic linking). */
+#define REFERENCE_FLAG_PRIVATE_DEFINED                3     /**< Defined private symbol (dynamic linking). */
+#define REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY     4     /**< Normal undefined private symbol. */
+#define REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY         5     /**< Lazy undefined private symbol. */
+
+#define REFERENCED_DYNAMICALLY          KU16_C(0x0010)    /**< Don't strip. */
+
+
+/** Get the dynamic library ordinal. */
+#define GET_LIBRARY_ORDINAL(n_desc)     \
+    (((n_desc) >> 8) & 0xff)
+/** Set the dynamic library ordinal. */
+#define SET_LIBRARY_ORDINAL(n_desc, ordinal) \
+    (n_desc) = (((n_desc) & 0xff) | (((ordinal) & 0xff) << 8))
+#define SELF_LIBRARY_ORDINAL            0x00                /**< Special ordinal for refering to onself. */
+#define MAX_LIBRARY_ORDINAL             0xfd                /**< Maximum ordinal number. */
+#define DYNAMIC_LOOKUP_ORDINAL          0xfe                /**< Special ordinal number for dynamic lookup. (Mac OS X 10.3 and later) */
+#define EXECUTABLE_ORDINAL              0xff                /**< Special ordinal number for the executable.  */
+
+
+/** Only MH_OBJECT: Never dead strip me! */
+#define N_NO_DEAD_STRIP                 KU16_C(0x0020)
+/** Not MH_OBJECT: Discarded symbol. */
+#define N_DESC_DISCARDED                KU16_C(0x0020)
+/** Weak external symbol. Symbol can be missing, in which case it's will have the value 0. */
+#define N_WEAK_REF                      KU16_C(0x0040)
+/** Weak symbol definition. The symbol can be overridden by another weak
+ * symbol already present or by a non-weak (strong) symbol definition.
+ * Currently only supported for coalesed symbols.
+ * @remark This bit means something differently for undefined symbols, see N_REF_TO_WEAK.
+ */
+#define N_WEAK_DEF                      KU16_C(0x0080)
+/** Reference to a weak symbol, resolve using flat namespace searching.
+ * @remark This bit means something differently for defined symbols, see N_WEAK_DEF. */
+#define N_REF_TO_WEAK                   KU16_C(0x0080)
+
+/** @} */
+
+/** @} */
+
+
+/** @defgroup grp_macho_o_relocs    Relocations
+ * @{ */
+
+/**
+ * Relocation entry.
+ *
+ * Differs from a.out in the meaning of r_symbolnum when r_extern=0 and
+ * that r_pad is made into r_type.
+ *
+ * @remark  This structure and type has been prefixed with macho_ to avoid
+ *          confusion with the original a.out type.
+ */
+typedef struct macho_relocation_info
+{
+    KI32        r_address;          /**< Section relative address of the fixup.
+                                         The top bit (signed) indicates that this is a scattered
+                                         relocation if set, see scattered_relocation_info_t. */
+    KU32        r_symbolnum : 24,   /**< r_extern=1: Symbol table index, relocate with the address of this symbol.
+                                         r_extern=0: Section ordinal, relocate with the address of this section. */
+                r_pcrel : 1,        /**< PC (program counter) relative fixup; subtract the fixup address. */
+                r_length : 2,       /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. */
+                r_extern : 1,       /**< External or internal fixup, decides the r_symbolnum interpretation.. */
+                r_type : 4;         /**< Relocation type; 0 is standard, non-zero are machine specific. */
+} macho_relocation_info_t;
+
+/** Special section ordinal value for absolute relocations. */
+#define R_ABS           0
+
+/** Flag in r_address indicating that the relocation is of the
+ * scattered_relocation_info_t kind and not macho_relocation_info_t. */
+#define R_SCATTERED     KU32_C(0x80000000)
+
+/**
+ * Scattered relocation.
+ *
+ * This is a hack mainly for RISC machines which restricts section size
+ * to 16MB among other things.
+ *
+ * The reason for the big/little endian differences here is of course because
+ * of the R_SCATTERED mask and the way bitfields are implemented by the
+ * C/C++ compilers.
+ */
+typedef struct scattered_relocation_info
+{
+#if K_ENDIAN == K_ENDIAN_LITTLE
+    KU32        r_address : 24,     /**< Section relative address of the fixup. (macho_relocation_info_t::r_address) */
+                r_type : 4,         /**< Relocation type; 0 is standard, non-zero are machine specific. (macho_relocation_info_t::r_type) */
+                r_length : 2,       /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. (macho_relocation_info_t::r_length) */
+                r_pcrel : 1,        /**< PC (program counter) relative fixup; subtract the fixup address. (macho_relocation_info_t::r_pcrel) */
+                r_scattered : 1;    /**< Set if scattered relocation, clear if normal relocation. */
+#elif K_ENDIAN == K_ENDIAN_BIG
+    KU32        r_scattered : 1,    /**< Set if scattered relocation, clear if normal relocation. */
+                r_pcrel : 1,        /**< PC (program counter) relative fixup; subtract the fixup address. (macho_relocation_info_t::r_pcrel) */
+                r_length : 2,       /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. (macho_relocation_info_t::r_length) */
+                r_type : 4,         /**< Relocation type; 0 is standard, non-zero are machine specific. (macho_relocation_info_t::r_type) */
+                r_address : 24;     /**< Section relative address of the fixup. (macho_relocation_info_t::r_address) */
+#else
+# error "Neither K_ENDIAN isn't LITTLE or BIG!"
+#endif
+    KI32        r_value;            /**< The value the fixup is refering to (without offset added). */
+} scattered_relocation_info_t;
+
+/**
+ * Relocation type values for a generic implementation (for r_type).
+ */
+typedef enum reloc_type_generic
+{
+    GENERIC_RELOC_VANILLA = 0,      /**< Standard relocation. */
+    GENERIC_RELOC_PAIR,             /**< Follows GENERIC_RELOC_SECTDIFF. */
+    GENERIC_RELOC_SECTDIFF,         /**< ??? */
+    GENERIC_RELOC_PB_LA_PTR,        /**< Prebound lazy pointer whatever that. */
+    GENERIC_RELOC_LOCAL_SECTDIFF    /**< ??? */
+} reloc_type_generic_t;
+
+/** @} */
+
+
+/** @} */
+#endif
+
Index: /trunk/include/k/kLdrFmts/mz.h
===================================================================
--- /trunk/include/k/kLdrFmts/mz.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/mz.h	(revision 2)
@@ -0,0 +1,45 @@
+/* $Id$ */
+/** @file
+ * MZ structures, types and defines.
+ */
+
+#ifndef ___k_kLdrFmts_mz_h___
+#define ___k_kLdrFmts_mz_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+
+#pragma pack(1) /* not required */
+
+typedef struct _IMAGE_DOS_HEADER
+{
+    KU16       e_magic;
+    KU16       e_cblp;
+    KU16       e_cp;
+    KU16       e_crlc;
+    KU16       e_cparhdr;
+    KU16       e_minalloc;
+    KU16       e_maxalloc;
+    KU16       e_ss;
+    KU16       e_sp;
+    KU16       e_csum;
+    KU16       e_ip;
+    KU16       e_cs;
+    KU16       e_lfarlc;
+    KU16       e_ovno;
+    KU16       e_res[4];
+    KU16       e_oemid;
+    KU16       e_oeminfo;
+    KU16       e_res2[10];
+    KU32       e_lfanew;
+} IMAGE_DOS_HEADER;
+typedef IMAGE_DOS_HEADER *PIMAGE_DOS_HEADER;
+
+#ifndef IMAGE_DOS_SIGNATURE
+# define IMAGE_DOS_SIGNATURE K_LE2H_U16('M' | ('Z' << 8))
+#endif
+
+#pragma pack()
+
+#endif
+
Index: /trunk/include/k/kLdrFmts/pe.h
===================================================================
--- /trunk/include/k/kLdrFmts/pe.h	(revision 2)
+++ /trunk/include/k/kLdrFmts/pe.h	(revision 2)
@@ -0,0 +1,481 @@
+/* $Id$ */
+/** @file
+ * PE structures, types and defines.
+ */
+
+#ifndef ___k_kLdrFmts_pe_h___
+#define ___k_kLdrFmts_pe_h___
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kTypes.h>
+#include <k/kDefs.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#ifndef IMAGE_NT_SIGNATURE
+# define  IMAGE_NT_SIGNATURE K_LE2H_U32('P' | ('E' << 8))
+#endif
+
+/* file header */
+#define  IMAGE_FILE_MACHINE_I386  0x014c
+#define  IMAGE_FILE_MACHINE_AMD64  0x8664
+
+#define  IMAGE_FILE_RELOCS_STRIPPED  0x0001
+#define  IMAGE_FILE_EXECUTABLE_IMAGE  0x0002
+#define  IMAGE_FILE_LINE_NUMS_STRIPPED  0x0004
+#define  IMAGE_FILE_LOCAL_SYMS_STRIPPED  0x0008
+#define  IMAGE_FILE_AGGRESIVE_WS_TRIM  0x0010
+#define  IMAGE_FILE_LARGE_ADDRESS_AWARE  0x0020
+#define  IMAGE_FILE_16BIT_MACHINE  0x0040
+#define  IMAGE_FILE_BYTES_REVERSED_LO  0x0080
+#define  IMAGE_FILE_32BIT_MACHINE  0x0100
+#define  IMAGE_FILE_DEBUG_STRIPPED  0x0200
+#define  IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP  0x0400
+#define  IMAGE_FILE_NET_RUN_FROM_SWAP  0x0800
+#define  IMAGE_FILE_SYSTEM  0x1000
+#define  IMAGE_FILE_DLL  0x2000
+#define  IMAGE_FILE_UP_SYSTEM_ONLY  0x4000
+#define  IMAGE_FILE_BYTES_REVERSED_HI  0x8000
+
+
+/* optional header */
+#define  IMAGE_NT_OPTIONAL_HDR32_MAGIC  0x10B
+#define  IMAGE_NT_OPTIONAL_HDR64_MAGIC  0x20B
+
+#define  IMAGE_SUBSYSTEM_UNKNOWN  0x0
+#define  IMAGE_SUBSYSTEM_NATIVE  0x1
+#define  IMAGE_SUBSYSTEM_WINDOWS_GUI  0x2
+#define  IMAGE_SUBSYSTEM_WINDOWS_CUI  0x3
+#define  IMAGE_SUBSYSTEM_OS2_GUI  0x4
+#define  IMAGE_SUBSYSTEM_OS2_CUI  0x5
+#define  IMAGE_SUBSYSTEM_POSIX_CUI  0x7
+
+#define  IMAGE_LIBRARY_PROCESS_INIT  0x0001
+#define  IMAGE_LIBRARY_PROCESS_TERM  0x0002
+#define  IMAGE_LIBRARY_THREAD_INIT  0x0004
+#define  IMAGE_LIBRARY_THREAD_TERM  0x0008
+#define  IMAGE_DLLCHARACTERISTICS_NO_ISOLATION  0x0200
+#define  IMAGE_DLLCHARACTERISTICS_NO_SEH  0x0400
+#define  IMAGE_DLLCHARACTERISTICS_NO_BIND  0x0800
+#define  IMAGE_DLLCHARACTERISTICS_WDM_DRIVER  0x2000
+#define  IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE  0x8000
+
+#define  IMAGE_NUMBEROF_DIRECTORY_ENTRIES  0x10
+
+#define  IMAGE_DIRECTORY_ENTRY_EXPORT  0x0
+#define  IMAGE_DIRECTORY_ENTRY_IMPORT  0x1
+#define  IMAGE_DIRECTORY_ENTRY_RESOURCE  0x2
+#define  IMAGE_DIRECTORY_ENTRY_EXCEPTION  0x3
+#define  IMAGE_DIRECTORY_ENTRY_SECURITY  0x4
+#define  IMAGE_DIRECTORY_ENTRY_BASERELOC  0x5
+#define  IMAGE_DIRECTORY_ENTRY_DEBUG  0x6
+#define  IMAGE_DIRECTORY_ENTRY_ARCHITECTURE  0x7
+#define  IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE
+#define  IMAGE_DIRECTORY_ENTRY_GLOBALPTR  0x8
+#define  IMAGE_DIRECTORY_ENTRY_TLS  0x9
+#define  IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG  0xa
+#define  IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT  0xb
+#define  IMAGE_DIRECTORY_ENTRY_IAT  0xc
+#define  IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT  0xd
+#define  IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR  0xe
+
+
+/* section header */
+#define  IMAGE_SIZEOF_SHORT_NAME  0x8
+
+#define  IMAGE_SCN_TYPE_REG  0x00000000
+#define  IMAGE_SCN_TYPE_DSECT  0x00000001
+#define  IMAGE_SCN_TYPE_NOLOAD  0x00000002
+#define  IMAGE_SCN_TYPE_GROUP  0x00000004
+#define  IMAGE_SCN_TYPE_NO_PAD  0x00000008
+#define  IMAGE_SCN_TYPE_COPY  0x00000010
+
+#define  IMAGE_SCN_CNT_CODE  0x00000020
+#define  IMAGE_SCN_CNT_INITIALIZED_DATA  0x00000040
+#define  IMAGE_SCN_CNT_UNINITIALIZED_DATA  0x00000080
+
+#define  IMAGE_SCN_LNK_OTHER  0x00000100
+#define  IMAGE_SCN_LNK_INFO  0x00000200
+#define  IMAGE_SCN_TYPE_OVER  0x00000400
+#define  IMAGE_SCN_LNK_REMOVE  0x00000800
+#define  IMAGE_SCN_LNK_COMDAT  0x00001000
+#define  IMAGE_SCN_MEM_PROTECTED  0x00004000
+#define  IMAGE_SCN_NO_DEFER_SPEC_EXC  0x00004000
+#define  IMAGE_SCN_GPREL  0x00008000
+#define  IMAGE_SCN_MEM_FARDATA  0x00008000
+#define  IMAGE_SCN_MEM_SYSHEAP  0x00010000
+#define  IMAGE_SCN_MEM_PURGEABLE  0x00020000
+#define  IMAGE_SCN_MEM_16BIT  0x00020000
+#define  IMAGE_SCN_MEM_LOCKED  0x00040000
+#define  IMAGE_SCN_MEM_PRELOAD  0x00080000
+
+#define  IMAGE_SCN_ALIGN_1BYTES  0x00100000
+#define  IMAGE_SCN_ALIGN_2BYTES  0x00200000
+#define  IMAGE_SCN_ALIGN_4BYTES  0x00300000
+#define  IMAGE_SCN_ALIGN_8BYTES  0x00400000
+#define  IMAGE_SCN_ALIGN_16BYTES  0x00500000
+#define  IMAGE_SCN_ALIGN_32BYTES  0x00600000
+#define  IMAGE_SCN_ALIGN_64BYTES  0x00700000
+#define  IMAGE_SCN_ALIGN_128BYTES  0x00800000
+#define  IMAGE_SCN_ALIGN_256BYTES  0x00900000
+#define  IMAGE_SCN_ALIGN_512BYTES  0x00A00000
+#define  IMAGE_SCN_ALIGN_1024BYTES  0x00B00000
+#define  IMAGE_SCN_ALIGN_2048BYTES  0x00C00000
+#define  IMAGE_SCN_ALIGN_4096BYTES  0x00D00000
+#define  IMAGE_SCN_ALIGN_8192BYTES  0x00E00000
+#define  IMAGE_SCN_ALIGN_MASK  0x00F00000
+
+#define  IMAGE_SCN_LNK_NRELOC_OVFL  0x01000000
+#define  IMAGE_SCN_MEM_DISCARDABLE  0x02000000
+#define  IMAGE_SCN_MEM_NOT_CACHED  0x04000000
+#define  IMAGE_SCN_MEM_NOT_PAGED  0x08000000
+#define  IMAGE_SCN_MEM_SHARED  0x10000000
+#define  IMAGE_SCN_MEM_EXECUTE  0x20000000
+#define  IMAGE_SCN_MEM_READ  0x40000000
+#define  IMAGE_SCN_MEM_WRITE  0x80000000
+
+
+/* relocations */
+#define  IMAGE_REL_BASED_ABSOLUTE  0x0
+#define  IMAGE_REL_BASED_HIGH  0x1
+#define  IMAGE_REL_BASED_LOW  0x2
+#define  IMAGE_REL_BASED_HIGHLOW  0x3
+#define  IMAGE_REL_BASED_HIGHADJ  0x4
+#define  IMAGE_REL_BASED_MIPS_JMPADDR  0x5
+#define  IMAGE_REL_BASED_SECTION  0x6
+#define  IMAGE_REL_BASED_REL32  0x7
+/*#define  IMAGE_REL_BASED_RESERVED1 0x8 */
+#define  IMAGE_REL_BASED_MIPS_JMPADDR16 0x9
+#define  IMAGE_REL_BASED_IA64_IMM64  0x9
+#define  IMAGE_REL_BASED_DIR64  0xa
+#define  IMAGE_REL_BASED_HIGH3ADJ 0xb
+
+/* imports */
+#define  IMAGE_ORDINAL_FLAG32  0x80000000
+#define  IMAGE_ORDINAL32(ord)  ((ord) &  0xffff)
+#define  IMAGE_SNAP_BY_ORDINAL32(ord)  (!!((ord) & IMAGE_ORDINAL_FLAG32))
+
+#define  IMAGE_ORDINAL_FLAG64  0x8000000000000000ULL
+#define  IMAGE_ORDINAL64(ord)  ((ord) &  0xffff)
+#define  IMAGE_SNAP_BY_ORDINAL64(ord)  (!!((ord) & IMAGE_ORDINAL_FLAG64))
+
+
+/* dll/tls entry points argument */
+#define DLL_PROCESS_DETACH      0
+#define DLL_PROCESS_ATTACH      1
+#define DLL_THREAD_ATTACH       2
+#define DLL_THREAD_DETACH       3
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+#pragma pack(4)
+
+typedef struct _IMAGE_FILE_HEADER
+{
+    KU16      Machine;
+    KU16      NumberOfSections;
+    KU32      TimeDateStamp;
+    KU32      PointerToSymbolTable;
+    KU32      NumberOfSymbols;
+    KU16      SizeOfOptionalHeader;
+    KU16      Characteristics;
+} IMAGE_FILE_HEADER;
+typedef IMAGE_FILE_HEADER *PIMAGE_FILE_HEADER;
+
+
+typedef struct _IMAGE_DATA_DIRECTORY
+{
+    KU32      VirtualAddress;
+    KU32      Size;
+} IMAGE_DATA_DIRECTORY;
+typedef IMAGE_DATA_DIRECTORY *PIMAGE_DATA_DIRECTORY;
+
+
+typedef struct _IMAGE_OPTIONAL_HEADER32
+{
+    KU16    Magic;
+    KU8     MajorLinkerVersion;
+    KU8     MinorLinkerVersion;
+    KU32    SizeOfCode;
+    KU32    SizeOfInitializedData;
+    KU32    SizeOfUninitializedData;
+    KU32    AddressOfEntryPoint;
+    KU32    BaseOfCode;
+    KU32    BaseOfData;
+    KU32    ImageBase;
+    KU32    SectionAlignment;
+    KU32    FileAlignment;
+    KU16    MajorOperatingSystemVersion;
+    KU16    MinorOperatingSystemVersion;
+    KU16    MajorImageVersion;
+    KU16    MinorImageVersion;
+    KU16    MajorSubsystemVersion;
+    KU16    MinorSubsystemVersion;
+    KU32    Win32VersionValue;
+    KU32    SizeOfImage;
+    KU32    SizeOfHeaders;
+    KU32    CheckSum;
+    KU16    Subsystem;
+    KU16    DllCharacteristics;
+    KU32    SizeOfStackReserve;
+    KU32    SizeOfStackCommit;
+    KU32    SizeOfHeapReserve;
+    KU32    SizeOfHeapCommit;
+    KU32    LoaderFlags;
+    KU32    NumberOfRvaAndSizes;
+    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER32;
+typedef IMAGE_OPTIONAL_HEADER32 *PIMAGE_OPTIONAL_HEADER32;
+
+typedef struct _IMAGE_OPTIONAL_HEADER64
+{
+    KU16    Magic;
+    KU8     MajorLinkerVersion;
+    KU8     MinorLinkerVersion;
+    KU32    SizeOfCode;
+    KU32    SizeOfInitializedData;
+    KU32    SizeOfUninitializedData;
+    KU32    AddressOfEntryPoint;
+    KU32    BaseOfCode;
+    KU64    ImageBase;
+    KU32    SectionAlignment;
+    KU32    FileAlignment;
+    KU16    MajorOperatingSystemVersion;
+    KU16    MinorOperatingSystemVersion;
+    KU16    MajorImageVersion;
+    KU16    MinorImageVersion;
+    KU16    MajorSubsystemVersion;
+    KU16    MinorSubsystemVersion;
+    KU32    Win32VersionValue;
+    KU32    SizeOfImage;
+    KU32    SizeOfHeaders;
+    KU32    CheckSum;
+    KU16    Subsystem;
+    KU16    DllCharacteristics;
+    KU64    SizeOfStackReserve;
+    KU64    SizeOfStackCommit;
+    KU64    SizeOfHeapReserve;
+    KU64    SizeOfHeapCommit;
+    KU32    LoaderFlags;
+    KU32    NumberOfRvaAndSizes;
+    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER64;
+typedef IMAGE_OPTIONAL_HEADER64 *PIMAGE_OPTIONAL_HEADER64;
+
+
+typedef struct _IMAGE_NT_HEADERS
+{
+    KU32 Signature;
+    IMAGE_FILE_HEADER FileHeader;
+    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} IMAGE_NT_HEADERS32;
+typedef IMAGE_NT_HEADERS32 *PIMAGE_NT_HEADERS32;
+
+typedef struct _IMAGE_NT_HEADERS64
+{
+    KU32 Signature;
+    IMAGE_FILE_HEADER FileHeader;
+    IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} IMAGE_NT_HEADERS64;
+typedef IMAGE_NT_HEADERS64 *PIMAGE_NT_HEADERS64;
+
+
+typedef struct _IMAGE_SECTION_HEADER
+{
+    KU8      Name[IMAGE_SIZEOF_SHORT_NAME];
+    union
+    {
+        KU32      PhysicalAddress;
+        KU32      VirtualSize;
+    } Misc;
+    KU32      VirtualAddress;
+    KU32      SizeOfRawData;
+    KU32      PointerToRawData;
+    KU32      PointerToRelocations;
+    KU32      PointerToLinenumbers;
+    KU16      NumberOfRelocations;
+    KU16      NumberOfLinenumbers;
+    KU32      Characteristics;
+} IMAGE_SECTION_HEADER;
+typedef IMAGE_SECTION_HEADER *PIMAGE_SECTION_HEADER;
+
+
+typedef struct _IMAGE_BASE_RELOCATION
+{
+    KU32      VirtualAddress;
+    KU32      SizeOfBlock;
+} IMAGE_BASE_RELOCATION;
+typedef IMAGE_BASE_RELOCATION *PIMAGE_BASE_RELOCATION;
+
+
+typedef struct _IMAGE_EXPORT_DIRECTORY
+{
+    KU32      Characteristics;
+    KU32      TimeDateStamp;
+    KU16      MajorVersion;
+    KU16      MinorVersion;
+    KU32      Name;
+    KU32      Base;
+    KU32      NumberOfFunctions;
+    KU32      NumberOfNames;
+    KU32      AddressOfFunctions;
+    KU32      AddressOfNames;
+    KU32      AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
+
+
+typedef struct _IMAGE_IMPORT_DESCRIPTOR
+{
+    union
+    {
+        KU32      Characteristics;
+        KU32      OriginalFirstThunk;
+    } u;
+    KU32      TimeDateStamp;
+    KU32      ForwarderChain;
+    KU32      Name;
+    KU32      FirstThunk;
+} IMAGE_IMPORT_DESCRIPTOR;
+typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR;
+
+
+typedef struct _IMAGE_IMPORT_BY_NAME
+{
+    KU16      Hint;
+    KU8      Name[1];
+} IMAGE_IMPORT_BY_NAME;
+typedef IMAGE_IMPORT_BY_NAME *PIMAGE_IMPORT_BY_NAME;
+
+
+/* The image_thunk_data32/64 structures are not very helpful except for getting RSI. keep them around till all the code has been converted. */
+typedef struct _IMAGE_THUNK_DATA64
+{
+    union
+    {
+        KU64      ForwarderString;
+        KU64      Function;
+        KU64      Ordinal;
+        KU64      AddressOfData;
+    } u1;
+} IMAGE_THUNK_DATA64;
+typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64;
+
+typedef struct _IMAGE_THUNK_DATA32
+{
+    union
+    {
+        KU32      ForwarderString;
+        KU32      Function;
+        KU32      Ordinal;
+        KU32      AddressOfData;
+    } u1;
+} IMAGE_THUNK_DATA32;
+typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32;
+
+
+typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32
+{
+    KU32      Size;
+    KU32      TimeDateStamp;
+    KU16      MajorVersion;
+    KU16      MinorVersion;
+    KU32      GlobalFlagsClear;
+    KU32      GlobalFlagsSet;
+    KU32      CriticalSectionDefaultTimeout;
+    KU32      DeCommitFreeBlockThreshold;
+    KU32      DeCommitTotalFreeThreshold;
+    KU32      LockPrefixTable;
+    KU32      MaximumAllocationSize;
+    KU32      VirtualMemoryThreshold;
+    KU32      ProcessHeapFlags;
+    KU32      ProcessAffinityMask;
+    KU16      CSDVersion;
+    KU16      Reserved1;
+    KU32      EditList;
+    KU32      SecurityCookie;
+    KU32      SEHandlerTable;
+    KU32      SEHandlerCount;
+} IMAGE_LOAD_CONFIG_DIRECTORY32;
+typedef IMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY32;
+
+typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64
+{
+    KU32      Size;
+    KU32      TimeDateStamp;
+    KU16      MajorVersion;
+    KU16      MinorVersion;
+    KU32      GlobalFlagsClear;
+    KU32      GlobalFlagsSet;
+    KU32      CriticalSectionDefaultTimeout;
+    KU64      DeCommitFreeBlockThreshold;
+    KU64      DeCommitTotalFreeThreshold;
+    KU64      LockPrefixTable;
+    KU64      MaximumAllocationSize;
+    KU64      VirtualMemoryThreshold;
+    KU64      ProcessAffinityMask;
+    KU32      ProcessHeapFlags;
+    KU16      CSDVersion;
+    KU16      Reserved1;
+    KU64      EditList;
+    KU64      SecurityCookie;
+    KU64      SEHandlerTable;
+    KU64      SEHandlerCount;
+} IMAGE_LOAD_CONFIG_DIRECTORY64;
+typedef IMAGE_LOAD_CONFIG_DIRECTORY64 *PIMAGE_LOAD_CONFIG_DIRECTORY64;
+
+typedef struct _IMAGE_DEBUG_DIRECTORY
+{
+    KU32      Characteristics;
+	KU32  TimeDateStamp;
+    KU16      MajorVersion;
+    KU16      MinorVersion;
+    KU32      Type;
+    KU32      SizeOfData;
+    KU32      AddressOfRawData;
+    KU32      PointerToRawData;
+} IMAGE_DEBUG_DIRECTORY;
+typedef IMAGE_DEBUG_DIRECTORY *PIMAGE_DEBUG_DIRECTORY;
+
+#define IMAGE_DEBUG_TYPE_UNKNOWN  0
+#define IMAGE_DEBUG_TYPE_COFF 1
+#define IMAGE_DEBUG_TYPE_CODEVIEW 2 /* 4.0 */
+#define IMAGE_DEBUG_TYPE_FPO 3 /* FPO = frame pointer omission */
+#define IMAGE_DEBUG_TYPE_MISC 4
+#define IMAGE_DEBUG_TYPE_EXCEPTION 5
+#define IMAGE_DEBUG_TYPE_FIXUP 6
+#define IMAGE_DEBUG_TYPE_BORLAND 9
+
+typedef struct _IMAGE_TLS_DIRECTORY32
+{
+    KU32      StartAddressOfRawData;
+    KU32      EndAddressOfRawData;
+    KU32      AddressOfIndex;
+    KU32      AddressOfCallBacks;
+    KU32      SizeOfZeroFill;
+    KU32      Characteristics;
+} IMAGE_TLS_DIRECTORY32;
+typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32;
+
+typedef struct _IMAGE_TLS_DIRECTORY64
+{
+    KU64      StartAddressOfRawData;
+    KU64      EndAddressOfRawData;
+    KU64      AddressOfIndex;
+    KU64      AddressOfCallBacks;
+    KU32      SizeOfZeroFill;
+    KU32      Characteristics;
+} IMAGE_TLS_DIRECTORY64;
+typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64;
+
+
+#pragma pack()
+
+#endif
+
Index: /trunk/include/k/kMagics.h
===================================================================
--- /trunk/include/k/kMagics.h	(revision 2)
+++ /trunk/include/k/kMagics.h	(revision 2)
@@ -0,0 +1,39 @@
+/* $Id$ */
+/** @file
+ * kMagics - Various Magic Constants.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#ifndef ___k_kMagics_h___
+#define ___k_kMagics_h___
+
+/** The magic for KRDR::u32Magic. (Katsu Aki (Katsuaki Nakamura))
+ * @ingroup grp_kRdrAll */
+#define KRDR_MAGIC          0x19610919
+/** The magic value for the debug module structure. (Some manga artist)
+ * @ingroup grp_kDbgAll */
+#define KDBGMOD_MAGIC       0x19200501
+
+#endif
+
Index: /trunk/include/k/kRdr.h
===================================================================
--- /trunk/include/k/kRdr.h	(revision 2)
+++ /trunk/include/k/kRdr.h	(revision 2)
@@ -0,0 +1,82 @@
+/* $Id$ */
+/** @file
+ * kRdr - The File Provider.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___kRdr_h___
+#define ___kRdr_h___
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+
+/** @defgroup grp_kRdr      kRdr - The File Provider
+ * @{ */
+
+/** @def KRDR_DECL
+ * Declares a kRdr function according to build context.
+ * @param type          The return type.
+ */
+#if defined(KRDR_BUILDING_DYNAMIC)
+# define KRDR_DECL(type)    K_DECL_EXPORT(type)
+#elif defined(KRDR_BUILT_DYNAMIC)
+# define KRDR_DECL(type)    K_DECL_IMPORT(type)
+#else
+# define KRDR_DECL(type)    type
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KRDR_DECL(int)      kRdrOpen(   PPKRDR ppRdr, const char *pszFilename);
+KRDR_DECL(int)      kRdrClose(    PKRDR pRdr);
+KRDR_DECL(int)      kRdrRead(     PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
+KRDR_DECL(int)      kRdrAllMap(   PKRDR pRdr, const void **ppvBits);
+KRDR_DECL(int)      kRdrAllUnmap( PKRDR pRdr, const void *pvBits);
+KRDR_DECL(KFOFF)    kRdrSize(     PKRDR pRdr);
+KRDR_DECL(KFOFF)    kRdrTell(     PKRDR pRdr);
+KRDR_DECL(const char *) kRdrName( PKRDR pRdr);
+KRDR_DECL(KIPTR)    kRdrNativeFH( PKRDR pRdr);
+KRDR_DECL(KSIZE)    kRdrPageSize( PKRDR pRdr);
+KRDR_DECL(int)      kRdrMap(      PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
+KRDR_DECL(int)      kRdrRefresh(  PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+KRDR_DECL(int)      kRdrProtect(  PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
+KRDR_DECL(int)      kRdrUnmap(    PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+KRDR_DECL(void)     kRdrDone(     PKRDR pRdr);
+
+KRDR_DECL(int)      kRdrBufOpen(PPKRDR ppRdr, const char *pszFilename);
+KRDR_DECL(int)      kRdrBufWrap(PPKRDR ppRdr, PKRDR pRdr, KBOOL fCloseIt);
+KRDR_DECL(KBOOL)    kRdrBufIsBuffered(PKRDR pRdr);
+KRDR_DECL(int)      kRdrBufLine(PKRDR pRdr, char *pszLine, KSIZE cbLine);
+KRDR_DECL(int)      kRdrBufLineEx(PKRDR pRdr, char *pszLine, KSIZE *pcbLine);
+KRDR_DECL(const char *) kRdrBufLineQ(PKRDR pRdr);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/include/k/kRdrAll.h
===================================================================
--- /trunk/include/k/kRdrAll.h	(revision 2)
+++ /trunk/include/k/kRdrAll.h	(revision 2)
@@ -0,0 +1,123 @@
+/* $Id$ */
+/** @file
+ * kRdr - The File Provider, All Details and Dependencies Included.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kRdrAll_h___
+#define ___k_kRdrAll_h___
+
+#include <k/kDefs.h>
+#include <k/kLdr.h>
+#include <k/kRdr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** @defgroup grp_kRdrAll   All
+ * @addtogroup grp_kRdr
+ * @{
+ */
+
+/**
+ * File provider instance operations.
+ */
+typedef struct KRDROPS
+{
+    /** The name of this file provider. */
+    const char *pszName;
+    /** Pointer to the next file provider. */
+    const struct KRDROPS *pNext;
+
+    /** Try create a new file provider instance.
+     *
+     * @returns 0 on success, OS specific error code on failure.
+     * @param   ppRdr       Where to store the file provider instance.
+     * @param   pszFilename The filename to open.
+     */
+    int     (* pfnCreate)(  PPKRDR ppRdr, const char *pszFilename);
+    /** Destroy the file provider instance.
+     *
+     * @returns 0 on success, OS specific error code on failure.
+     *          On failure, the file provider instance will be in an indeterminate state - don't touch it!
+     * @param   pRdr        The file provider instance.
+     */
+    int     (* pfnDestroy)( PKRDR pRdr);
+    /** @copydoc kRdrRead */
+    int     (* pfnRead)(    PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
+    /** @copydoc kRdrAllMap */
+    int     (* pfnAllMap)(  PKRDR pRdr, const void **ppvBits);
+    /** @copydoc kRdrAllUnmap */
+    int     (* pfnAllUnmap)(PKRDR pRdr, const void *pvBits);
+    /** @copydoc kRdrSize */
+    KFOFF   (* pfnSize)(    PKRDR pRdr);
+    /** @copydoc kRdrTell */
+    KFOFF   (* pfnTell)(    PKRDR pRdr);
+    /** @copydoc kRdrName */
+    const char * (* pfnName)(PKRDR pRdr);
+    /** @copydoc kRdrNativeFH */
+    KIPTR  (* pfnNativeFH)(PKRDR pRdr);
+    /** @copydoc kRdrPageSize */
+    KSIZE   (* pfnPageSize)(PKRDR pRdr);
+    /** @copydoc kRdrMap */
+    int     (* pfnMap)(     PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
+    /** @copydoc kRdrRefresh */
+    int     (* pfnRefresh)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+    /** @copydoc kRdrProtect */
+    int     (* pfnProtect)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
+    /** @copydoc kRdrUnmap */
+    int     (* pfnUnmap)(   PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+    /** @copydoc kRdrDone */
+    void    (* pfnDone)(    PKRDR pRdr);
+    /** The usual non-zero dummy that makes sure we've initialized all members. */
+    KU32    u32Dummy;
+} KRDROPS;
+/** Pointer to file provider operations. */
+typedef KRDROPS *PKRDROPS;
+/** Pointer to const file provider operations. */
+typedef const KRDROPS *PCKRDROPS;
+
+
+/**
+ * File provider instance core.
+ */
+typedef struct KRDR
+{
+    /** Magic number (KRDR_MAGIC). */
+    KU32        u32Magic;
+    /** Pointer to the file provider operations. */
+    PCKRDROPS   pOps;
+} KRDR;
+
+void    kRdrAddProvider(PKRDROPS pAdd);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
Index: /trunk/include/k/kTypes.h
===================================================================
--- /trunk/include/k/kTypes.h	(revision 2)
+++ /trunk/include/k/kTypes.h	(revision 2)
@@ -0,0 +1,402 @@
+/* $Id$ */
+/** @file
+ *
+ * kTypes - Typedefs And Related Constants And Macros.
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ___k_kTypes_h___
+#define ___k_kTypes_h___
+
+#include <k/kDefs.h>
+
+/** @defgroup grp_kTypes    kTypes - Typedefs And Related Constants And Macros
+ * @{
+ */
+
+/** @typedef KI64
+ * 64-bit signed integer. */
+/** @typedef KU64
+ * 64-bit unsigned integer. */
+/** @def KI64_C
+ * 64-bit signed integer constant.
+ * @param c         The constant value. */
+/** @def KU64_C
+ * 64-bit unsigned integer constant.
+ * @param c         The constant value. */
+/** @def KI64_PRI
+ * 64-bit signed integer printf format. */
+/** @def KU64_PRI
+ * 64-bit unsigned integer printf format. */
+/** @def KX64_PRI
+ * 64-bit signed and unsigned integer hexadecimal printf format. */
+
+/** @typedef KI32
+ * 32-bit signed integer. */
+/** @typedef KU32
+ * 32-bit unsigned integer. */
+/** @def KI32_C
+ * 32-bit signed integer constant.
+ * @param c         The constant value. */
+/** @def KU32_C
+ * 32-bit unsigned integer constant.
+ * @param c         The constant value. */
+/** @def KI32_PRI
+ * 32-bit signed integer printf format. */
+/** @def KU32_PRI
+ * 32-bit unsigned integer printf format. */
+/** @def KX32_PRI
+ * 32-bit signed and unsigned integer hexadecimal printf format. */
+
+/** @typedef KI16
+ * 16-bit signed integer. */
+/** @typedef KU16
+ * 16-bit unsigned integer. */
+/** @def KI16_C
+ * 16-bit signed integer constant.
+ * @param c         The value. */
+/** @def KU16_C
+ * 16-bit unsigned integer constant.
+ * @param c         The value. */
+/** @def KI16_PRI
+ * 16-bit signed integer printf format. */
+/** @def KU16_PRI
+ * 16-bit unsigned integer printf format. */
+/** @def KX16_PRI
+ * 16-bit signed and unsigned integer hexadecimal printf format. */
+
+/** @typedef KI8
+ * 8-bit signed integer. */
+/** @typedef KU8
+ * 8-bit unsigned integer. */
+/** @def KI8_C
+ * 8-bit signed integer constant.
+ * @param c         The constant value. */
+/** @def KU8_C
+ * 8-bit unsigned integer constant.
+ * @param c         The constant value. */
+/** @def KI8_PRI
+ * 8-bit signed integer printf format. */
+/** @def KU8_PRI
+ * 8-bit unsigned integer printf format. */
+/** @def KX8_PRI
+ * 8-bit signed and unsigned integer hexadecimal printf format. */
+
+/** @typedef KSIZE
+ * Memory size type; unsigned integer. */
+/** @typedef KSSIZE
+ * Memory size type; signed integer. */
+/** @def KSIZE_C
+ * Memory size constant.
+ * @param c         The constant value. */
+/** @def KSSIZE_C
+ * Memory size constant.
+ * @param c         The constant value. */
+/** @def KSIZE_MAX
+ * Memory size max constant.*/
+/** @def KSSIZE_MAX
+ * Memory size max constant.*/
+/** @def KSSIZE_MIN
+ * Memory size min constant.*/
+/** @def KSIZE_PRI
+ * Memory size printf format. */
+/** @def KSSIZE_PRI
+ * Memory size printf format. */
+
+/** @typedef KIPTR
+ * Signed integer type capable of containing a pointer value.  */
+/** @typedef KUPTR
+ * Unsigned integer type capable of containing a pointer value.  */
+/** @def KIPTR_C
+ * Signed pointer constant.
+ * @param c         The constant value. */
+/** @def KUPTR_C
+ * Unsigned pointer constant.
+ * @param c         The constant value. */
+/** @def KIPTR_MAX
+ * Signed pointer max constant.*/
+/** @def KIPTR_MIN
+ * Signed pointer min constant.*/
+/** @def KUPTR_MAX
+ * Unsigned pointer max constant.*/
+/** @def KIPTR_PRI
+ * Signed pointer printf format. */
+/** @def KUPTR_PRI
+ * Unsigned pointer printf format. */
+
+
+#if K_ARCH_BITS == 32
+  /* ASSUMES int == long == 32-bit, short == 16-bit, char == 8-bit. */
+# ifdef _MSC_VER
+typedef signed __int64          KI64;
+typedef unsigned __int64        KU64;
+#define KI64_PRI                "I64d"
+#define KU64_PRI                "I64u"
+#define KX64_PRI                "I64x"
+# else
+typedef signed long long int    KI64;
+typedef unsigned long long int  KU64;
+#define KI64_PRI                "lld"
+#define KU64_PRI                "llu"
+#define KX64_PRI                "llx"
+# endif
+typedef signed int              KI32;
+typedef unsigned int            KU32;
+typedef signed short int        KI16;
+typedef unsigned short int      KU16;
+typedef signed char             KI8;
+typedef unsigned char           KU8;
+#define KI64_C(c)               (c ## LL)
+#define KU64_C(c)               (c ## ULL)
+#define KI32_C(c)               (c)
+#define KU32_C(c)               (c)
+#define KI16_C(c)               (c)
+#define KU16_C(c)               (c)
+#define KI8_C(c)                (c)
+#define KU8_C(c)                (c)
+
+#define KI32_PRI                "d"
+#define KU32_PRI                "u"
+#define KX32_PRI                "x"
+#define KI16_PRI                "d"
+#define KU16_PRI                "u"
+#define KX16_PRI                "x"
+#define KI8_PRI                 "d"
+#define KU8_PRI                 "u"
+#define KX8_PRI                 "x"
+
+typedef KI32                    KSSIZE;
+#define KSSIZE(c)               KI32_C(c)
+#define KSSIZE_MAX              KI32_MAX
+#define KSSIZE_MIN              KI32_MIN
+#define KSSIZE_PRI              KX32_PRI
+
+typedef KU32                    KSIZE;
+#define KSIZE_C(c)              KU32_C(c)
+#define KSIZE_MAX               KU32_MAX
+#define KSIZE_PRI               KX32_PRI
+#define KIPTR_C(c)              KI32_C(c)
+
+typedef KI32                    KIPTR;
+#define KIPTR_MAX               KI32_MAX
+#define KIPTR_MIN               KI32_MIN
+#define KIPTR_PRI               KX32_PRI
+
+typedef KU32                    KUPTR;
+#define KUPTR_C(c)              KU32_C(c)
+#define KUPTR_MAX               KU32_MAX
+#define KUPTR_PRI               KX32_PRI
+
+
+#elif K_ARCH_BITS == 64
+
+# if K_OS == K_OS_WINDOWS
+#  if _MSC_VER
+typedef signed __int64          KI64;
+typedef unsigned __int64        KU64;
+#   define KI64_PRI             "I64d"
+#   define KU64_PRI             "I64u"
+#   define KX64_PRI             "I64x"
+#  else
+typedef signed long long int    KI64;
+typedef unsigned long long int  KU64;
+#   define KI64_PRI              "lld"
+#   define KU64_PRI              "llu"
+#   define KX64_PRI              "llx"
+#  endif
+#  define KI64_C(c)             (c ## LL)
+#  define KU64_C(c)             (c ## ULL)
+# else
+typedef signed long int         KI64;
+typedef unsigned long int       KU64;
+#  define KI64_C(c)             (c ## L)
+#  define KU64_C(c)             (c ## UL)
+#  define KI64_PRI              "ld"
+#  define KU64_PRI              "lu"
+#  define KX64_PRI              "lx"
+# endif
+typedef signed int              KI32;
+typedef unsigned int            KU32;
+typedef signed short            KI16;
+typedef unsigned short          KU16;
+typedef signed char             KI8;
+typedef unsigned char           KU8;
+#define KI32_C(c)               (c)
+#define KU32_C(c)               (c)
+#define KI16_C(c)               (c)
+#define KU16_C(c)               (c)
+#define KI8_C(c)                (c)
+#define KU8_C(c)                (c)
+
+#define KI32_PRI                "d"
+#define KU32_PRI                "u"
+#define KX32_PRI                "x"
+#define KI16_PRI                "d"
+#define KU16_PRI                "u"
+#define KX16_PRI                "x"
+#define KI8_PRI                 "d"
+#define KU8_PRI                 "u"
+#define KX8_PRI                 "x"
+
+typedef KI64                    KSSIZE;
+#define KSSIZE(c)               KI64_C(c)
+#define KSSIZE_MAX              KI64_MAX
+#define KSSIZE_MIN              KI64_MIN
+#define KSSIZE_PRI              KX64_PRI
+
+typedef KU64                    KSIZE;
+#define KSIZE_C(c)              KU64_C(c)
+#define KSIZE_MAX               KU64_MAX
+#define KSIZE_PRI               KX64_PRI
+
+typedef KI64                    KIPTR;
+#define KIPTR_C(c)              KI64_C(c)
+#define KIPTR_MAX               KI64_MAX
+#define KIPTR_MIN               KI64_MIN
+#define KIPTR_PRI               KX64_PRI
+
+typedef KU64                    KUPTR;
+#define KUPTR_C(c)              KU64_C(c)
+#define KUPTR_MAX               KU64_MAX
+#define KUPTR_PRI               KX64_PRI
+
+#else
+# error "Port Me"
+#endif
+
+
+/** Min KI8 value. */
+#define KI8_MIN                 (KI8_C(-0x7f) - 1)
+/** Min KI16 value. */
+#define KI16_MIN                (KI16_C(-0x7fff) - 1)
+/** Min KI32 value. */
+#define KI32_MIN                (KI32_C(-0x7fffffff) - 1)
+/** Min KI64 value. */
+#define KI64_MIN                (KI64_C(-0x7fffffffffffffff) - 1)
+/** Max KI8 value. */
+#define KI8_MAX                 KI8_C(0x7f)
+/** Max KI16 value. */
+#define KI16_MAX                KI16_C(0x7fff)
+/** Max KI32 value. */
+#define KI32_MAX                KI32_C(0x7fffffff)
+/** Max KI64 value. */
+#define KI64_MAX                KI64_C(0x7fffffffffffffff)
+/** Max KU8 value. */
+#define KU8_MAX                 KU8_C(0xff)
+/** Max KU16 value. */
+#define KU16_MAX                KU16_C(0xffff)
+/** Max KU32 value. */
+#define KU32_MAX                KU32_C(0xffffffff)
+/** Max KU64 value. */
+#define KU64_MAX                KU64_C(0xffffffffffffffff)
+
+/** File offset. */
+typedef KI64                    KFOFF;
+/** Pointer a file offset. */
+typedef KFOFF                  *PFOFF;
+/** Pointer a const file offset. */
+typedef KFOFF                  *PCFOFF;
+/** The min value for the KFOFF type. */
+#define KFOFF_MIN               KI64_MIN
+/** The max value for the KFOFF type. */
+#define KFOFF_MAX               KI64_MAX
+/** File offset contstant.
+ * @param c         The constant value. */
+#define KFOFF_C(c)              KI64_C(c)
+/** File offset printf format. */
+#define KFOFF_PRI               KI64_PRI
+
+
+/**
+ * Memory Protection.
+ */
+typedef enum KPROT
+{
+    /** The usual invalid 0. */
+    KPROT_INVALID = 0,
+    /** No access (page not present). */
+    KPROT_NOACCESS,
+    /** Read only. */
+    KPROT_READONLY,
+    /** Read & write. */
+    KPROT_READWRITE,
+    /** Read & copy on write. */
+    KPROT_WRITECOPY,
+    /** Execute only. */
+    KPROT_EXECUTE,
+    /** Execute & read. */
+    KPROT_EXECUTE_READ,
+    /** Execute, read & write. */
+    KPROT_EXECUTE_READWRITE,
+    /** Execute, read & copy on write. */
+    KPROT_EXECUTE_WRITECOPY,
+    /** The usual end value. (exclusive) */
+    KPROT_END,
+    /** Blow the type up to 32-bits. */
+    KPROT_32BIT_HACK = 0x7fffffff
+} KPROT;
+/** Pointer to a memory protection enum. */
+typedef KPROT                  *PKPROT;
+/** Pointer to a const memory protection enum. */
+typedef KPROT const            *PCKPROT;
+
+/** Boolean.
+ * This can be used as a tri-state type, but then you *must* do == checks. */
+typedef KI8                     KBOOL;
+/** Pointer to a boolean value. */
+typedef KBOOL                  *PKBOOL;
+/** Pointer to a const boolean value. */
+typedef KBOOL const            *PCKBOOL;
+/** Maxium value the KBOOL type can hold (officially). */
+#define KBOOL_MIN               KI8_C(-1)
+/** Maxium value the KBOOL type can hold (officially). */
+#define KBOOL_MAX               KI8_C(1)
+/** The KBOOL printf format. */
+#define KBOOL_PRI               KU8_PRI
+/** Boolean true constant. */
+#define K_TRUE                  KI8_C(1)
+/** Boolean false constant. */
+#define K_FALSE                 KI8_C(0)
+/** Boolean unknown constant (the third state). */
+#define K_UNKNOWN               KI8_C(-1)
+
+
+
+/** @name   Forward Declarations / Handle Types.
+ * @{ */
+
+/** Pointer to a file provider instance. */
+typedef struct KRDR *PKRDR;
+/** Pointer to a file provider instance pointer. */
+typedef struct KRDR **PPKRDR;
+
+/** Pointer to a loader segment. */
+typedef struct KLDRSEG *PKLDRSEG;
+/** Pointer to a loader segment. */
+typedef const struct KLDRSEG *PCKLDRSEG;
+
+/** @} */
+
+/** @} */
+
+#endif
+
Index: /trunk/kCpu/Makefile.kmk
===================================================================
--- /trunk/kCpu/Makefile.kmk	(revision 2)
+++ /trunk/kCpu/Makefile.kmk	(revision 2)
@@ -0,0 +1,38 @@
+# $Id$
+## @file
+# kCpu - The CPU and Architecture API, sub-makefile.
+#
+
+#
+# Copyright (c) 2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kStuff 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+DEPTH ?= ../..
+SUB_DEPTH = ..
+include $(PATH_KBUILD)/subheader.kmk
+
+LIBRARIES += kCpuStatic
+kCpuStatic_TEMPLATE = kStuffLIB
+kCpuStatic_SOURCES = \
+	kCpuCompare.c \
+	kCpuGetArchAndCpu.c
+
+include $(PATH_KBUILD)/subfooter.kmk
+
Index: /trunk/kCpu/kCpuCompare.c
===================================================================
--- /trunk/kCpu/kCpuCompare.c	(revision 2)
+++ /trunk/kCpu/kCpuCompare.c	(revision 2)
@@ -0,0 +1,133 @@
+/* $Id$ */
+/** @file
+ * kCpu - kCpuCompare.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kCpu.h>
+#include <k/kErrors.h>
+
+
+/**
+ * Compares arch+cpu some code was generated for with a arch+cpu for executing it
+ * to see if it'll work out fine or not.
+ *
+ * @returns 0 if the code is compatible with the cpu.
+ * @returns KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE if the arch+cpu isn't compatible with the code.
+ *
+ * @param   enmCodeArch The architecture the code was generated for.
+ * @param   enmCodeCpu  The cpu the code was generated for.
+ * @param   enmArch     The architecture to run it on.
+ * @param   enmCpu      The cpu to run it on.
+ */
+KCPU_DECL(int) kCpuCompare(KCPUARCH enmCodeArch, KCPU enmCodeCpu, KCPUARCH enmArch, KCPU enmCpu)
+{
+    /*
+     * Compare arch and cpu.
+     */
+    if (enmCodeArch != enmArch)
+        return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+
+    /* exact match is nice. */
+    if (enmCodeCpu == enmCpu)
+        return 0;
+
+    switch (enmArch)
+    {
+        case K_ARCH_X86_16:
+            if (enmCpu < KCPU_FIRST_X86_16 || enmCpu > KCPU_LAST_X86_16)
+                return KERR_INVALID_PARAMETER;
+
+            /* intel? */
+            if (enmCodeCpu <= KCPU_CORE2_16)
+            {
+                /* also intel? */
+                if (enmCpu <= KCPU_CORE2_16)
+                    return enmCodeCpu <= enmCpu ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+                switch (enmCpu)
+                {
+                    case KCPU_K6_16:
+                        return enmCodeCpu <= KCPU_I586 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+                    case KCPU_K7_16:
+                    case KCPU_K8_16:
+                    default:
+                        return enmCodeCpu <= KCPU_I686 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+                }
+            }
+            /* amd */
+            return enmCpu >= KCPU_K6_16 && enmCpu <= KCPU_K8_16
+                    ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+
+        case K_ARCH_X86_32:
+            if (enmCpu < KCPU_FIRST_X86_32 || enmCpu > KCPU_LAST_X86_32)
+                return KERR_INVALID_PARAMETER;
+
+            /* blend? */
+            if (enmCodeCpu == KCPU_X86_32_BLEND)
+                return 0;
+
+            /* intel? */
+            if (enmCodeCpu <= KCPU_CORE2_32)
+            {
+                /* also intel? */
+                if (enmCpu <= KCPU_CORE2_32)
+                    return enmCodeCpu <= enmCpu ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+                switch (enmCpu)
+                {
+                    case KCPU_K6:
+                        return enmCodeCpu <= KCPU_I586 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+                    case KCPU_K7:
+                    case KCPU_K8_32:
+                    default:
+                        return enmCodeCpu <= KCPU_I686 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+                }
+            }
+            /* amd */
+            return enmCpu >= KCPU_K6 && enmCpu <= KCPU_K8_32
+                    ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+
+        case K_ARCH_AMD64:
+            if (enmCpu < KCPU_FIRST_AMD64 || enmCpu > KCPU_LAST_AMD64)
+                return KERR_INVALID_PARAMETER;
+
+            /* blend? */
+            if (enmCodeCpu == KCPU_AMD64_BLEND)
+                return 0;
+            /* this is simple for now. */
+            return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+
+        default:
+            break;
+    }
+    return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+}
+
Index: /trunk/kCpu/kCpuGetArchAndCpu.c
===================================================================
--- /trunk/kCpu/kCpuGetArchAndCpu.c	(revision 2)
+++ /trunk/kCpu/kCpuGetArchAndCpu.c	(revision 2)
@@ -0,0 +1,59 @@
+/* $Id$ */
+/** @file
+ * kCpu - kCpuGetArchAndCpu.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kCpu.h>
+
+
+/**
+ * Gets the arch+cpu of the calling cpu.
+ *
+ * @param   penmArch    Where to store the cpu architecture.
+ * @param   penmCpu     Where to store the cpu brand/model.
+ */
+KCPU_DECL(void) kCpuGetArchAndCpu(PKCPUARCH penmArch, PKCPU penmCpu)
+{
+#if K_ARCH == K_ARCH_AMD64
+    *penmArch = KCPUARCH_AMD64;
+    *penmCpu = KCPU_AMD64_BLEND; /** @todo check it using cpu. */
+
+#elif K_ARCH == K_ARCH_X86_32
+    *penmArch = KCPUARCH_X86_32;
+    *penmCpu = KCPU_X86_32_BLEND; /** @todo check it using cpu. */
+
+#else
+# error "Port me"
+#endif
+}
+
Index: /trunk/kDbg/Makefile.kmk
===================================================================
--- /trunk/kDbg/Makefile.kmk	(revision 2)
+++ /trunk/kDbg/Makefile.kmk	(revision 2)
@@ -0,0 +1,66 @@
+# $Id$
+## @file
+# kDbg - The Debug Info Reader, sub-makefile.
+#
+
+#
+# Copyright (c) 2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kStuff 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+DEPTH ?= ../..
+SUB_DEPTH = ..
+include $(PATH_KBUILD)/subheader.kmk
+
+#
+# kDbg - The profiler module.
+#
+#DLLS += kDbg - disabled for now.
+kDbg_TEMPLATE = kStuffDLL
+kDbg_DEFS = KDBG_BUILDING KDBG_RESIDES_IN_DLL
+kDbg_SOURCES := \
+	kDbgModule.cpp \
+	kDbgLine.cpp \
+	kDbgSymbol.cpp
+
+kDbg_SOURCES.win += \
+	kDbgModWinDbgHelp.cpp
+
+#
+# kDbgStatic - The profiler module.
+#
+LIBRARIES += kDbgStatic
+kDbgStatic_TEMPLATE = kStuffLIB
+kDbgStatic_DEFS = KDBG_BUILDING
+kDbgStatic_SOURCES = $(kDbg_SOURCES)
+
+#
+# kDbgDump - Test program which dumps whatever is thrown at it.
+#
+PROGRAMS += kDbgDump
+kDbgDump_TEMPLATE = kStuffEXE
+kDbgDump_SOURCES = kDbgDump.cpp
+kDbgDump_LIBS = \
+	$(TARGET_kDbgStatic) \
+	$(subst kDbg,kLdr,$(TARGET_kDbgStatic)) \
+	$(subst kDbg,kRdr,$(TARGET_kDbgStatic)) \
+	$(subst kDbg,kHlpCRT,$(TARGET_kDbgStatic))
+
+# Generate the rules
+include $(PATH_KBUILD)/subfooter.kmk
+
Index: /trunk/kDbg/kDbgDump.cpp
===================================================================
--- /trunk/kDbg/kDbgDump.cpp	(revision 2)
+++ /trunk/kDbg/kDbgDump.cpp	(revision 2)
@@ -0,0 +1,176 @@
+/* $Id$ */
+/** @file
+ * kDbgDump - Debug Info Dumper.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kDbg.h>
+#include <string.h>
+#include <stdio.h>
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** @name Options
+ * @{ */
+static int g_fGlobalSyms = 1;
+static int g_fPrivateSyms = 1;
+static int g_fLineNumbers = 0;
+/** @} */
+
+
+/**
+ * Dumps one file.
+ *
+ * @returns main exit status.
+ * @param   pszFile     The file to dump (path to it).
+ */
+static int DumpFile(const char *pszFile)
+{
+    PKDBGMOD pDbgMod;
+    int rc = kDbgModuleOpen(&pDbgMod, pszFile, NULL);
+    if (rc)
+    {
+        printf("kDbgDump: error: kDbgModuleOpen('%s',) failed with rc=%d.\n", pszFile, rc);
+        return 1;
+    }
+
+
+
+    return 0;
+}
+
+
+/**
+ * Prints the version number
+ * @return 0
+ */
+static int ShowVersion()
+{
+    printf("kDbgDump v0.0.1\n");
+    return 0;
+}
+
+
+/**
+ * Prints the program syntax.
+ *
+ * @returns 1
+ * @param   argv0   The program name.
+ */
+static int ShowSyntax(const char *argv0)
+{
+    ShowVersion();
+    printf("syntax: %s [options] <files>\n"
+           "\n",
+           argv0);
+    return 1;
+}
+
+int main(int argc, char **argv)
+{
+    int rcRet = 0;
+
+    /*
+     * Parse arguments.
+     */
+    int fArgsDone = 0;
+    for (int i = 1; i < argc; i++)
+    {
+        const char *psz = argv[i];
+
+        if (!fArgsDone && psz[0] == '-' && psz[1])
+        {
+            /* convert long option to short. */
+            if (*++psz == '-')
+            {
+                psz++;
+                if (!*psz) /* -- */
+                {
+                    fArgsDone = 1;
+                    continue;
+                }
+                if (!strcmp(psz, "line-numbers"))
+                    psz = "l";
+                else if (!strcmp(psz, "no-line-numbers"))
+                    psz = "L";
+                else if (!strcmp(psz, "global-syms")    || !strcmp(psz, "public-syms"))
+                    psz = "g";
+                else if (!strcmp(psz, "no-global-syms") || !strcmp(psz, "no-public-syms"))
+                    psz = "G";
+                else if (!strcmp(psz, "privat-syms")    || !strcmp(psz, "local-syms"))
+                    psz = "p";
+                else if (!strcmp(psz, "no-privat-syms") || !strcmp(psz, "no-local-syms"))
+                    psz = "P";
+                else if (!strcmp(psz, "version"))
+                    psz = "v";
+                else if (!strcmp(psz, "help"))
+                    psz = "h";
+                else
+                {
+                    fprintf(stderr, "%s: syntax error: unknown option '--%s'\n", argv[0], psz);
+                    return 1;
+                }
+            }
+
+            /* eat short options. */
+            while (*psz)
+                switch (*psz++)
+                {
+                    case 'l': g_fLineNumbers = 1; break;
+                    case 'L': g_fLineNumbers = 0; break;
+                    case 'p': g_fPrivateSyms = 1; break;
+                    case 'P': g_fPrivateSyms = 0; break;
+                    case 'g': g_fGlobalSyms = 1; break;
+                    case 'G': g_fGlobalSyms = 0; break;
+                    case '?':
+                    case 'H':
+                    case 'h': return ShowSyntax(argv[0]);
+                    case 'v': return ShowVersion();
+                    default:
+                        fprintf(stderr, "%s: syntax error: unknown option '-%c'.\n", argv[0], psz[-1]);
+                        return 1;
+                }
+        }
+        else
+        {
+            /* Dump does it's own bitching if something goes wrong. */
+            int rc = DumpFile(psz);
+            if (rc && !rcRet)
+                rc = rcRet;
+        }
+    }
+
+    return rcRet;
+}
+
Index: /trunk/kDbg/kDbgHlp.h
===================================================================
--- /trunk/kDbg/kDbgHlp.h	(revision 2)
+++ /trunk/kDbg/kDbgHlp.h	(revision 2)
@@ -0,0 +1,308 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, Internal Header.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef ___kDbgHlp_h___
+#define ___kDbgHlp_h___
+
+#include <k/kDbgBase.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** @defgroup grp_kDbgHlpHeap   kDbg Internal Heap APIs.
+ * @internal
+ * @{
+ */
+
+/**
+ * Allocates memory.
+ *
+ * @returns Pointer to the allocated memory.
+ *          NULL on failure.
+ * @param   cb      The number of bytes to allocate.
+ */
+void *kDbgHlpAlloc(size_t cb);
+
+/**
+ * Allocates memory like kDbgHlpAlloc, except that it's zeroed.
+ *
+ * @returns Pointer to the allocated memory.
+ *          NULL on failure.
+ * @param   cb      The number of bytes to allocate.
+ */
+void *kDbgHlpAllocZ(size_t cb);
+
+/**
+ * Combination of kDbgHlpAlloc and memcpy.
+ *
+ * @returns Pointer to the duplicate.
+ *          NULL on failure.
+ *
+ * @param   pv      The memory to be duplicate.
+ * @param   cb      The size of the block.
+ */
+void *kDbgHlpAllocDup(const void *pv, size_t cb);
+
+/**
+ * Reallocates a memory block returned by kDbgHlpAlloc, kDbgHlpAllocZ
+ * kDbgHlpAllocDup or this function.
+ *
+ * The content of new memory added to the memory block is undefined.
+ *
+ * @returns Pointer to the allocated memory.
+ *          NULL on failure, the old block remains intact.
+ * @param   pv      The memory block to reallocate.
+ *                  If NULL this function will work like kDbgHlpAlloc.
+ * @param   cb      The number of bytes to allocate.
+ *                  If 0 this function will work like kDbgHlpFree.
+ */
+void *kDbgHlpRealloc(void *pv, size_t cb);
+
+/**
+ * Frees memory allocated by kDbgHlpAlloc, kDbgHlpAllocZ
+ * kDbgHlpAllocDup, or kDbgHlpRealloc.
+ *
+ * @param pv
+ */
+void kDbgHlpFree(void *pv);
+
+/** @} */
+
+
+/** @defgroup grp_kDbgHlpFile   kDbg Internal File Access APIs.
+ * @internal
+ * @{
+ */
+/**
+ * Opens the specified file as read-only, buffered if possible.
+ *
+ * @returns 0 on success, or the appropriate KDBG_ERR_* on failure.
+ *
+ * @param   pszFilename     The file to open.
+ * @param   ppFile          Where to store the handle to the open file.
+ */
+int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile);
+
+
+/**
+ * Closes a file opened by kDbgHlpOpenRO.
+ *
+ * @param   pFile           The file handle.
+ */
+void kDbgHlpClose(PKDBGHLPFILE pFile);
+
+/**
+ * Gets the native file handle.
+ *
+ * @return  The native file handle.
+ *          -1 on failure.
+ * @param   pFile           The file handle.
+ */
+uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile);
+
+/**
+ * Gets the size of an open file.
+ *
+ * @returns The file size in bytes on success.
+ *          On failure -1 is returned.
+ * @param   pFile           The file handle.
+ */
+int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile);
+
+/**
+ * Reads a number of bytes at a specified file location.
+ *
+ * This will change the current file position to off + cb on success,
+ * while on failure the position will be undefined.
+ *
+ * @returns The file size in bytes on success.
+ *          On failure -1 is returned.
+ * @param   pFile           The file handle.
+ * @param   off             Where to read.
+ * @param   pv              Where to store the data.
+ * @param   cb              How much to read.
+ */
+int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb);
+
+/**
+ * Reads a number of bytes at the current file position.
+ *
+ * This will advance the current file position by cb bytes on success
+ * while on failure the position will be undefined.
+ *
+ * @returns The file size in bytes on success.
+ *          On failure -1 is returned.
+ * @param   pFile           The file handle.
+ * @param   pv              Where to store the data.
+ * @param   cb              How much to read.
+ * @param   off             Where to read.
+ */
+int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb);
+
+/**
+ * Sets the current file position.
+ *
+ * @returns 0 on success, and KDBG_ERR_* on failure.
+ * @param   pFile           The file handle.
+ * @param   off             The desired file position.
+ */
+int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off);
+
+/**
+ * Move the file position relative to the current one.
+ *
+ * @returns 0 on success, and KDBG_ERR_* on failure.
+ * @param   pFile           The file handle.
+ * @param   off             How much to move the file position by.
+ */
+int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off);
+
+/**
+ * Move the file position relative to the end of the file.
+ *
+ * @returns 0 on success, and KDBG_ERR_* on failure.
+ * @param   pFile           The file handle.
+ * @param   off             The offset relative to the end, positive number.
+ */
+int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off);
+
+/**
+ * Gets the current file position.
+ *
+ * @returns The current file position on success.
+ *          -1 on failure.
+ * @param   pFile           The file handle.
+ */
+int64_t kDbgHlpTell(PKDBGHLPFILE pFile);
+
+/** @} */
+
+/** @defgroup grp_kDbgHlpAssert     kDbg Internal Assertion Macros.
+ * @internal
+ * @{
+ */
+
+#ifdef _MSC_VER
+# define kDbgAssertBreakpoint() do { __debugbreak(); } while (0)
+#else
+# define kDbgAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0)
+#endif
+
+/**
+ * Helper function that displays the first part of the assertion message.
+ *
+ * @param   pszExpr         The expression.
+ * @param   pszFile         The file name.
+ * @param   iLine           The line number is the file.
+ * @param   pszFunction     The function name.
+ */
+void kDbgAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction);
+
+/**
+ * Helper function that displays custom assert message.
+ *
+ * @param   pszFormat       Format string that get passed to vprintf.
+ * @param   ...             Format arguments.
+ */
+void kDbgAssertMsg2(const char *pszFormat, ...);
+
+
+#ifdef KDBG_STRICT
+
+# define kDbgAssert(expr) \
+    do { \
+        if (!(expr)) \
+        { \
+            kDbgAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kDbgAssertBreakpoint(); \
+        }
+    } while (0)
+
+# define kDbgAssertReturn(expr, rcRet) \
+    do { \
+        if (!(expr)) \
+        { \
+            kDbgAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kDbgAssertBreakpoint(); \
+            return (rcRet); \
+        }
+    } while (0)
+
+# define kDbgAssertMsg(expr, msg) \
+    do { \
+        if (!(expr)) \
+        { \
+            kDbgAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kDbgAssertMsg2 msg; \
+            kDbgAssertBreakpoint(); \
+        }
+    } while (0)
+
+# define kDbgAssertMsgReturn(expr, msg, rcRet) \
+    do { \
+        if (!(expr)) \
+        { \
+            kDbgAssertMsg1(#expr, __FILE__, __LINE__, __FUNCTION__); \
+            kDbgAssertMsg2 msg; \
+            kDbgAssertBreakpoint(); \
+            return (rcRet); \
+        }
+    } while (0)
+
+#else   /* !KDBG_STRICT */
+# define kDbgAssert(expr)                       do { } while (0)
+# define kDbgAssertReturn(expr, rcRet)          do { if (!(expr)) return (rcRet); } while (0)
+# define kDbgAssertMsg(expr, msg)               do { } while (0)
+# define kDbgAssertMsgReturn(expr, msg, rcRet)  do { if (!(expr)) return (rcRet); } while (0)
+#endif  /* !KDBG_STRICT */
+
+#define kDbgAssertPtr(ptr)                      kDbgAssertMsg(KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kDbgAssertPtrReturn(ptr, rcRet)         kDbgAssertMsgReturn(KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kDbgAssertPtrNull(ptr)                  kDbgAssertMsg(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kDbgAssertPtrNullReturn(ptr, rcRet)     kDbgAssertMsgReturn(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kDbgAssertRC(rc)                        kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc)))
+#define kDbgAssertRCReturn(rc, rcRet)           kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet))
+#define kDbgAssertFailed()                      kDbgAssert(0)
+#define kDbgAssertFailedReturn(rcRet)           kDbgAssertReturn(0, (rcRet))
+#define kDbgAssertMsgFailed(msg)                kDbgAssertMsg(0, msg)
+#define kDbgAssertMsgFailedReturn(msg, rcRet)   kDbgAssertMsgReturn(0, msg, (rcRet))
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
Index: /trunk/kDbg/kDbgHlpCrt.cpp
===================================================================
--- /trunk/kDbg/kDbgHlpCrt.cpp	(revision 2)
+++ /trunk/kDbg/kDbgHlpCrt.cpp	(revision 2)
@@ -0,0 +1,239 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, Helpers, CRT Based Implementation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kDbgHlp.h"
+#include "kDbg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef _MSC_VER
+# include <io.h>
+#endif
+
+
+
+/**
+ * The stdio base implementation of KDBGHLPFILE.
+ */
+typedef struct KDBGHLPFILE
+{
+    /** Pointer to the stdio file stream. */
+    FILE *pStrm;
+} KDBGHLPFILE;
+
+/** @def HAVE_FSEEKO
+ * Define HAVE_FSEEKO to indicate that fseeko and ftello should be used. */
+#if !defined(_MSC_VER)
+# define HAVE_FSEEKO
+#endif
+
+
+void *kDbgHlpAlloc(size_t cb)
+{
+    return malloc(cb);
+}
+
+
+void *kDbgHlpAllocZ(size_t cb)
+{
+    return calloc(1, cb);
+}
+
+
+void *kDbgHlpAllocDup(const void *pv, size_t cb)
+{
+    void *pvNew = malloc(cb);
+    if (pvNew)
+        memcpy(pvNew, pv, cb);
+    return pvNew;
+}
+
+
+void *kDbgHlpReAlloc(void *pv, size_t cb)
+{
+    return realloc(pv, cb);
+}
+
+
+void kDbgHlpFree(void *pv)
+{
+    free(pv);
+}
+
+
+int kDbgHlpCrtConvErrno(int rc)
+{
+    switch (rc)
+    {
+        case 0:             return 0;
+        case EINVAL:        return KERR_INVALID_PARAMETER;
+        case ENOMEM:        return KERR_NO_MEMORY;
+        case EISDIR:
+        case ENOENT:        return KERR_FILE_NOT_FOUND;
+        default:            return KERR_GENERAL_FAILURE;
+    }
+}
+
+
+int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile)
+{
+    PKDBGHLPFILE pFile = (PKDBGHLPFILE)kDbgHlpAlloc(sizeof(*pFile));
+    if (!pFile)
+        return KERR_NO_MEMORY;
+
+    pFile->pStrm = fopen(pszFilename, "rb");
+    if (pFile->pStrm)
+    {
+        *ppFile = pFile;
+        return 0;
+    }
+    return kDbgHlpCrtConvErrno(errno);
+}
+
+
+void kDbgHlpClose(PKDBGHLPFILE pFile)
+{
+    if (pFile)
+    {
+        fclose(pFile->pStrm);
+        pFile->pStrm = NULL;
+        kDbgHlpFree(pFile);
+    }
+}
+
+
+uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile)
+{
+    int fd = fileno(pFile->pStrm);
+#ifdef _MSC_VER
+    return _get_osfhandle(fd);
+#else
+    return fd;
+#endif
+}
+
+
+int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile)
+{
+    int64_t cbFile;
+    int64_t offCur = kDbgHlpTell(pFile);
+    if (offCur >= 0)
+    {
+        if (kDbgHlpSeekByEnd(pFile, 0) == 0)
+            cbFile = kDbgHlpTell(pFile);
+        else
+            cbFile = -1;
+        kDbgHlpSeek(pFile, offCur);
+    }
+    return cbFile;
+}
+
+
+int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb)
+{
+    int rc  = kDbgHlpSeek(pFile, off);
+    if (!rc)
+        rc = kDbgHlpRead(pFile, pv, cb);
+    return rc;
+}
+
+
+int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb)
+{
+    if (fread(pv, cb, 1, pFile->pStrm) == 1)
+        return 0;
+    return -1;
+}
+
+
+int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off)
+{
+#ifdef HAVE_FSEEKO
+    if (!fseeko(pFile->pStrm, off, SEEK_SET))
+        return 0;
+#else
+    long l = (long)off;
+    if (l != off)
+        return KERR_OUT_OF_RANGE;
+    if (!fseek(pFile->pStrm, l, SEEK_SET))
+        return 0;
+#endif
+    return kDbgHlpCrtConvErrno(errno);
+}
+
+
+int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off)
+{
+#ifdef HAVE_FSEEKO
+    if (!fseeko(pFile->pStrm, off, SEEK_CUR))
+        return 0;
+#else
+    long l = (long)off;
+    if (l != off)
+        return KERR_OUT_OF_RANGE;
+    if (!fseek(pFile->pStrm, l, SEEK_CUR))
+        return 0;
+#endif
+    return kDbgHlpCrtConvErrno(errno);
+}
+
+
+int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off)
+{
+#ifdef HAVE_FSEEKO
+    if (!fseeko(pFile->pStrm, -off, SEEK_END))
+        return 0;
+#else
+    long l = (long)off;
+    if (l != off)
+        return KERR_OUT_OF_RANGE;
+    if (!fseek(pFile->pStrm, -l, SEEK_END))
+        return 0;
+#endif
+    return kDbgHlpCrtConvErrno(errno);
+}
+
+
+int64_t kDbgHlpTell(PKDBGHLPFILE pFile)
+{
+#ifdef HAVE_FSEEKO
+    return ftello(pFile->pStrm);
+#else
+    return ftell(pFile->pStrm);
+#endif
+}
+
Index: /trunk/kDbg/kDbgInternal.h
===================================================================
--- /trunk/kDbg/kDbgInternal.h	(revision 2)
+++ /trunk/kDbg/kDbgInternal.h	(revision 2)
@@ -0,0 +1,139 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, Internal Header.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef ___kDbgInternal_h___
+#define ___kDbgInternal_h___
+
+#include <k/kHlpAssert.h>
+#include <k/kMagics.h>
+#include <k/kErrors.h>
+#include <k/kDbgAll.h>
+
+
+/** @defgroup grp_kDbgInternal  Internal
+ * @internal
+ * @addtogroup grp_kDbg
+ * @{
+ */
+
+/** @def KDBG_STRICT
+ * If defined the kDbg assertions and other runtime checks will be enabled. */
+#ifdef K_ALL_STRICT
+# undef KDBG_STRICT
+# define KDBG_STRICT
+#endif
+
+/** @name Our Assert macros
+ * @{ */
+#ifdef KDBG_STRICT
+# define kDbgAssert(expr)                       kHlpAssert(expr)
+# define kDbgAssertReturn(expr, rcRet)          kHlpAssertReturn(expr, rcRet)
+# define kDbgAssertReturnVoid(expr)             kHlpAssertReturnVoid(expr)
+# define kDbgAssertMsg(expr, msg)               kHlpAssertMsg(expr, msg)
+# define kDbgAssertMsgReturn(expr, msg, rcRet)  kHlpAssertMsgReturn(expr, msg, rcRet)
+# define kDbgAssertMsgReturnVoid(expr, msg)     kHlpAssertMsgReturnVoid(expr, msg)
+#else   /* !KDBG_STRICT */
+# define kDbgAssert(expr)                       do { } while (0)
+# define kDbgAssertReturn(expr, rcRet)          do { if (!(expr)) return (rcRet); } while (0)
+# define kDbgAssertMsg(expr, msg)               do { } while (0)
+# define kDbgAssertMsgReturn(expr, msg, rcRet)  do { if (!(expr)) return (rcRet); } while (0)
+#endif  /* !KDBG_STRICT */
+
+#define kDbgAssertPtr(ptr)                      kDbgAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kDbgAssertPtrReturn(ptr, rcRet)         kDbgAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kDbgAssertPtrReturnVoid(ptr)            kDbgAssertMsgReturnVoid(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)))
+#define kDbgAssertPtrNull(ptr)                  kDbgAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kDbgAssertPtrNullReturn(ptr, rcRet)     kDbgAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kDbgAssertPtrNullReturnVoid(ptr)        kDbgAssertMsgReturnVoid(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)))
+#define kDbgAssertRC(rc)                        kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc)))
+#define kDbgAssertRCReturn(rc, rcRet)           kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet))
+#define kDbgAssertRCReturnVoid(rc)              kDbgAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)))
+#define kDbgAssertFailed()                      kDbgAssert(0)
+#define kDbgAssertFailedReturn(rcRet)           kDbgAssertReturn(0, (rcRet))
+#define kDbgAssertFailedReturnVoid()            kDbgAssertReturnVoid(0)
+#define kDbgAssertMsgFailed(msg)                kDbgAssertMsg(0, msg)
+#define kDbgAssertMsgFailedReturn(msg, rcRet)   kDbgAssertMsgReturn(0, msg, (rcRet))
+#define kDbgAssertMsgFailedReturnVoid(msg)      kDbgAssertMsgReturnVoid(0, msg)
+/** @} */
+
+/** Return / crash validation of a reader argument. */
+#define KDBGMOD_VALIDATE_EX(pDbgMod, rc) \
+    do  { \
+        kDbgAssertPtrReturn((pDbgMod), (rc)); \
+        kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, (rc)); \
+        kDbgAssertReturn((pDbgMod)->pOps != NULL, (rc)); \
+    } while (0)
+
+/** Return / crash validation of a reader argument. */
+#define KDBGMOD_VALIDATE(pDbgMod) \
+    do  { \
+        kDbgAssertPtrReturn((pDbgMod), KERR_INVALID_POINTER); \
+        kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, KERR_INVALID_HANDLE); \
+        kDbgAssertReturn((pDbgMod)->pOps != NULL, KERR_INVALID_HANDLE); \
+    } while (0)
+
+/** Return / crash validation of a reader argument. */
+#define KDBGMOD_VALIDATE_VOID(pDbgMod) \
+    do  { \
+        kDbgAssertPtrReturnVoid((pDbgMod)); \
+        kDbgAssertReturnVoid((pDbgMod)->u32Magic == KDBGMOD_MAGIC); \
+        kDbgAssertReturnVoid((pDbgMod)->pOps != NULL); \
+    } while (0)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @name Built-in Debug Module Readers
+ * @{ */
+extern KDBGMODOPS const g_kDbgModWinDbgHelpOpen;
+extern KDBGMODOPS const g_kDbgModLdr;
+extern KDBGMODOPS const g_kDbgModCv8;
+extern KDBGMODOPS const g_kDbgModDwarf;
+extern KDBGMODOPS const g_kDbgModHll;
+extern KDBGMODOPS const g_kDbgModStabs;
+extern KDBGMODOPS const g_kDbgModSym;
+extern KDBGMODOPS const g_kDbgModMapILink;
+extern KDBGMODOPS const g_kDbgModMapMSLink;
+extern KDBGMODOPS const g_kDbgModMapNm;
+extern KDBGMODOPS const g_kDbgModMapWLink;
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
Index: /trunk/kDbg/kDbgLine.cpp
===================================================================
--- /trunk/kDbg/kDbgLine.cpp	(revision 2)
+++ /trunk/kDbg/kDbgLine.cpp	(revision 2)
@@ -0,0 +1,80 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Read, Line Numbers.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+
+
+/**
+ * Duplicates a line number.
+ *
+ * To save heap space, the returned line number will not own more heap space
+ * than it strictly need to. So, it's not possible to append stuff to the symbol
+ * or anything of that kind.
+ *
+ * @returns Pointer to the duplicate.
+ *          This must be freed using kDbgSymbolFree().
+ * @param   pLine       The line number to be duplicated.
+ */
+KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine)
+{
+    kDbgAssertPtrReturn(pLine, NULL);
+    KSIZE cb = K_OFFSETOF(KDBGLINE, szFile[pLine->cchFile + 1]);
+    PKDBGLINE pNewLine = (PKDBGLINE)kHlpDup(pLine, cb);
+    if (pNewLine)
+        pNewLine->cbSelf = cb;
+    return pNewLine;
+}
+
+
+/**
+ * Frees a line number obtained from the kDbg API.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pLine isn't a valid pointer.
+ *
+ * @param   pLine       The line number to be freed. The null pointer is ignored.
+ */
+KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine)
+{
+    if (pLine)
+    {
+        kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER);
+        pLine->cbSelf = 0;
+        kHlpFree(pLine);
+    }
+    return 0;
+}
+
Index: /trunk/kDbg/kDbgModLdr.cpp
===================================================================
--- /trunk/kDbg/kDbgModLdr.cpp	(revision 2)
+++ /trunk/kDbg/kDbgModLdr.cpp	(revision 2)
@@ -0,0 +1,110 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, kLdr Based.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kDbg.h>
+#include "kLdr.h"
+#include "kDbgInternal.h"
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * A kLdr based debug reader.
+ */
+typedef struct KDBGMODLDR
+{
+    /** The common module core. */
+    KDBGMOD     Core;
+    /** Pointer to the loader module. */
+    PKLDRMOD    pLdrMod;
+} KDBGMODLDR, *PKDBGMODLDR;
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQueryLine
+ */
+static int kDbgModPeQueryLine(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGLINE pLine)
+{
+    //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod;
+    return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQuerySymbol
+ */
+static int kDbgModPeQuerySymbol(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
+{
+    //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod;
+    return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnClose
+ */
+static int kDbgModLdrClose(PKDBGMOD pMod)
+{
+    //PKDBGMODLDr pThis = (PKDBGMODLDR)pMod;
+    return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydocs  KDBGMODOPS::pfnOpen.
+ */
+static int kDbgModLdrOpen(PKDBGHLPFILE pFile, KFOFF off, KFOFF cb, PKLDRMOD pLdrMod, PKDBGMOD *ppMod)
+{
+    return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * Methods for a PE module.
+ */
+const KDBGMODOPS g_kDbgModPeOps =
+{
+    "kLdr",
+    kDbgModLdrOpen,
+    kDbgModLdrClose,
+    kDbgModLdrQuerySymbol,
+    kDbgModLdrQueryLine
+    "kLdr"
+};
+
+
+
+
Index: /trunk/kDbg/kDbgModPE.cpp
===================================================================
--- /trunk/kDbg/kDbgModPE.cpp	(revision 2)
+++ /trunk/kDbg/kDbgModPE.cpp	(revision 2)
@@ -0,0 +1,386 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, PE Module (Generic).
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kDbg.h"
+#include "kDbgInternal.h"
+#include <kLdrModPE.h>
+#include <string.h>
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * A dbghelp based PE debug reader.
+ */
+typedef struct KDBGMODPE
+{
+    /** The common module core. */
+    KDBGMOD     Core;
+    /** The image size. */
+    uint32_t    cbImage;
+    /** The number of sections. (We've added the implicit header section.) */
+    int32_t     cSections;
+    /** The section headers (variable size). The first section is the
+     * implicit header section.*/
+    IMAGE_SECTION_HEADER aSections[1];
+} KDBGMODPE, *PKDBGMODPE;
+
+
+/**
+ * Calcs the RVA for a segment:offset address.
+ *
+ * @returns IPRT status code.
+ *
+ * @param   pModPe      The PE debug module instance.
+ * @param   iSegment    The segment number. Special segments are dealt with as well.
+ * @param   off         The segment offset.
+ * @param   puRVA       Where to store the RVA on success.
+ */
+static int kDbgModPeSegOffToRVA(PKDBGMODPE pModPe, int32_t iSegment, KDBGADDR off, uint32_t *puRVA)
+{
+    if (iSegment >= 0)
+    {
+        kDbgAssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModPe->cSections),
+                        KDBG_ERR_INVALID_ADDRESS);
+        kDbgAssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize,
+                        ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModPe->aSections[iSegment].Misc.VirtualSize),
+                        KDBG_ERR_INVALID_ADDRESS);
+        *puRVA = pModPe->aSections[iSegment].VirtualAddress + (uint32_t)off;
+        return 0;
+    }
+
+    if (iSegment == KDBGSEG_RVA)
+    {
+        kDbgAssertMsgReturn(off < pModPe->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModPe->cbImage),
+                            KDBG_ERR_INVALID_ADDRESS);
+        *puRVA = (uint32_t)off;
+        return 0;
+    }
+    kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS);
+}
+
+
+/**
+ * Calcs the segment:offset address for a RVA.
+ *
+ * @returns IPRT status code.
+ *
+ * @param   pModPe      The PE debug module instance.
+ * @param   uRVA        The RVA.
+ * @param   piSegment   Where to store the segment number.
+ * @param   poff        Where to store the segment offset.
+ */
+static int kDbgModPeRVAToSegOff(PKDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, KDBGADDR *poff)
+{
+    kDbgAssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModPe->cbImage),
+                        KDBG_ERR_INVALID_ADDRESS);
+    for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++)
+    {
+        /** @todo should probably be less strict about address in the alignment gaps. */
+        uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress;
+        if (off < pModPe->aSections[iSegment].Misc.VirtualSize)
+        {
+            *poff = off;
+            *piSegment = iSegment;
+            return 0;
+        }
+    }
+    kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS);
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQueryLine
+ */
+static int kDbgModPeQueryLine(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGLINE pLine)
+{
+    PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
+
+    /*
+     * Translate the address to an RVA.
+     */
+    uint32_t uRVA;
+    int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
+    if (!rc)
+    {
+#if 0
+        DWORD64 off;
+        IMAGEHLP_LINE64 Line;
+        Line.SizeOfStruct = sizeof(Line);
+        if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line))
+        {
+            pLine->RVA = (KDBGADDR)(Line.Address - pModPe->ImageBase);
+            rc = kDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment);
+            pLine->iLine = Line.LineNumber;
+            pLine->cchFile = strlen(Line.FileName);
+            if (pLine->cchFile >= sizeof(pLine->szFile))
+                pLine->cchFile = sizeof(pLine->szFile) - 1;
+            memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1);
+        }
+        else
+        {
+            DWORD Err = GetLastError();
+            rc = kDbgModPeConvWinError(Err);
+        }
+#endif
+        rc = KERR_NOT_IMPLEMENTED;
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQuerySymbol
+ */
+static int kDbgModPeQuerySymbol(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
+{
+    PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
+
+    /*
+     * Translate the address to an RVA.
+     */
+    uint32_t uRVA;
+    int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
+    if (!rc)
+    {
+#if 0
+        DWORD64 off;
+        union
+        {
+            SYMBOL_INFO Sym;
+            char        achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX];
+        } Buf;
+        Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
+        Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX;
+        if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym))
+        {
+            pSym->cb     = Buf.Sym.Size;
+            pSym->fFlags = 0;
+            if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
+                pSym->fFlags |= KDBGSYM_FLAGS_CODE;
+            else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
+                pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
+            else
+                pSym->fFlags |= KDBGSYM_FLAGS_DATA;
+            if (Buf.Sym.Flags & SYMFLAG_EXPORT)
+                pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED;
+            if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
+            {
+                pSym->iSegment   = KDBGSEG_ABS;
+                pSym->offSegment = (KDBGADDR)Buf.Sym.Value;
+                pSym->RVA        = (KDBGADDR)Buf.Sym.Value;
+            }
+            else
+            {
+                pSym->RVA        = (KDBGADDR)(Buf.Sym.Address - pModPe->ImageBase);
+                rc = kDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment);
+            }
+            pSym->cchName = (uint16_t)Buf.Sym.NameLen;
+            if (pSym->cchName >= sizeof(pSym->szName))
+                pSym->cchName = sizeof(pSym->szName) - 1;
+            memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
+            pSym->szName[Buf.Sym.NameLen] = '\0';
+        }
+        else
+        {
+            DWORD Err = GetLastError();
+            rc = kDbgModPeConvWinError(Err);
+        }
+#endif
+        rc = KERR_NOT_IMPLEMENTED;
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnClose
+ */
+static int kDbgModPeClose(PKDBGMOD pMod)
+{
+    PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
+
+    //if (g_pfnSymCleanup(pModPe->hSymInst))
+    //    return 0;
+    //
+    //DWORD Err = GetLastError();
+    //int rc = kDbgModPeConvWinError(Err);
+    //kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
+    //return rc;
+    return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * Opens the debug info for a PE image using the windows dbghelp library.
+ *
+ * @returns IPRT status code.
+ *
+ * @param   pFile               The handle to the module.
+ * @param   offHdr              The offset of the PE header.
+ * @param   pszModulePath       The path to the module.
+ * @param   ppDbgMod            Where to store the module handle.
+ *
+ */
+int kdbgModPEOpen(PKDBGHLPFILE pFile, int64_t offHdr, const char *pszModulePath, PKDBGMOD *ppDbgMod)
+{
+    /*
+     * We need to read the section headers and get the image size.
+     */
+    IMAGE_FILE_HEADER FHdr;
+    int rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr));
+    kDbgAssertRCReturn(rc, rc);
+
+    uint32_t cbImage;
+    if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
+        rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage),
+                           &cbImage, sizeof(cbImage));
+    else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
+        rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage),
+                           &cbImage, sizeof(cbImage));
+    else
+        kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT);
+    kDbgAssertRCReturn(rc, rc);
+
+    /*
+     * Allocate the module and read/construct the section headers.
+     */
+    PKDBGMODPE pModPe = (PKDBGMODPE)kDbgHlpAlloc(KDBG_OFFSETOF(KDBGMODPE, aSections[FHdr.NumberOfSections + 2]));
+    kDbgAssertReturn(pModPe, KERR_NO_MEMORY);
+    pModPe->Core.u32Magic   = KDBGMOD_MAGIC;
+    pModPe->Core.pOps       = &g_kDbgModPeOps;
+    pModPe->Core.pFile      = pFile;
+    pModPe->cbImage         = cbImage;
+    pModPe->cSections       = 1 + FHdr.NumberOfSections;
+    rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader,
+                       &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections);
+    if (!rc)
+    {
+        PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0];
+        memcpy(pSH->Name, "headers", sizeof(pSH->Name));
+        pSH->Misc.VirtualSize       = pModPe->aSections[1].VirtualAddress;
+        pSH->VirtualAddress         = 0;
+        pSH->SizeOfRawData          = pSH->Misc.VirtualSize;
+        pSH->PointerToRawData       = 0;
+        pSH->PointerToRelocations   = 0;
+        pSH->PointerToLinenumbers   = 0;
+        pSH->NumberOfRelocations    = 0;
+        pSH->NumberOfLinenumbers    = 0;
+        pSH->Characteristics        = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
+
+        uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress
+                         + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
+        if (uTheEnd < cbImage)
+        {
+            pSH = &pModPe->aSections[pModPe->cSections++];
+            memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
+            pSH->Misc.VirtualSize       = cbImage - uTheEnd;
+            pSH->VirtualAddress         = uTheEnd;
+            pSH->SizeOfRawData          = pSH->Misc.VirtualSize;
+            pSH->PointerToRawData       = 0;
+            pSH->PointerToRelocations   = 0;
+            pSH->PointerToLinenumbers   = 0;
+            pSH->NumberOfRelocations    = 0;
+            pSH->NumberOfLinenumbers    = 0;
+            pSH->Characteristics        = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
+        }
+
+#if 0
+        /*
+         * Find a new dbghelp handle.
+         *
+         * We assume 4GB of handles outlast most debugging sessions, or in anyways that
+         * when we start reusing handles they are no longer in use. :-)
+         */
+        static volatile uint32_t s_u32LastHandle = 1;
+        HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
+        while (     hSymInst == INVALID_HANDLE_VALUE
+               ||   hSymInst == (HANDLE)0
+               ||   hSymInst == GetCurrentProcess())
+            hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
+
+        /*
+         * Initialize dbghelp and try open the specified module.
+         */
+        if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
+        {
+            g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
+
+            kDbgHlpSeek(pFile, 0); /* don't know if this is required or not... */
+            DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0);
+            if (ImageBase)
+            {
+                pModPe->hSymInst    = hSymInst;
+                pModPe->ImageBase   = ImageBase;
+                *ppDbgMod = &pModPe->Core;
+                return rc;
+            }
+
+            DWORD Err = GetLastError();
+            rc = kDbgModPeConvWinError(Err);
+            kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc));
+            g_pfnSymCleanup(hSymInst);
+        }
+        else
+        {
+            DWORD Err = GetLastError();
+            rc = kDbgModPeConvWinError(Err);
+            kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
+        }
+#endif
+        rc = KERR_NOT_IMPLEMENTED;
+    }
+    else
+        kDbgAssertRC(rc);
+
+    kDbgHlpFree(pModPe);
+    return rc;
+}
+
+
+/**
+ * Methods for a PE module.
+ */
+const KDBGMODOPS g_kDbgModPeOps =
+{
+    "PE",
+    kDbgModPeClose,
+    kDbgModPeQuerySymbol,
+    kDbgModPeQueryLine
+};
+
+
+
Index: /trunk/kDbg/kDbgModWinDbgHelp.cpp
===================================================================
--- /trunk/kDbg/kDbgModWinDbgHelp.cpp	(revision 2)
+++ /trunk/kDbg/kDbgModWinDbgHelp.cpp	(revision 2)
@@ -0,0 +1,726 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, DbgHelp Based Reader.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <Windows.h>
+#define _IMAGEHLP64
+#include <DbgHelp.h>
+
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The dbghelp.dll module handle. */
+static HMODULE g_hDbgHelp = NULL;
+/** Pointer to the dbhelp.dll SymInitialize function. */
+static BOOL (WINAPI *g_pfnSymInitialize)(IN HANDLE,IN LPSTR,IN BOOL);
+/** Pointer to the dbhelp.dll SymCleanup function. */
+static BOOL (WINAPI *g_pfnSymCleanup)(IN HANDLE);
+/** Pointer to the dbhelp.dll SymSetOptions function. */
+static DWORD (WINAPI *g_pfnSymSetOptions)(IN DWORD);
+/** Pointer to the dbhelp.dll SymLoadModule64 function. */
+static DWORD64 (WINAPI *g_pfnSymLoadModule64)(IN HANDLE, IN HANDLE, IN PCSTR, IN PCSTR ModuleName, IN DWORD64, IN DWORD);
+/** Pointer to the dbhelp.dll SymFromAddr function. */
+static DWORD (WINAPI *g_pfnSymFromAddr)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PSYMBOL_INFO);
+/** Pointer to the dbhelp.dll SymGetLineFromAddr64 function. */
+static DWORD (WINAPI *g_pfnSymGetLineFromAddr64)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PIMAGEHLP_LINE64);
+
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * A dbghelp based PE debug reader.
+ */
+typedef struct KDBGMODDBGHELP
+{
+    /** The common module core. */
+    KDBGMOD     Core;
+    /** The image base. */
+    DWORD64     ImageBase;
+    /** The "process" handle we present dbghelp. */
+    HANDLE      hSymInst;
+    /** The image size. */
+    KU32        cbImage;
+    /** The number of sections. (We've added the implicit header section.) */
+    KI32        cSections;
+    /** The section headers (variable size). The first section is the
+     * implicit header section.*/
+    IMAGE_SECTION_HEADER    aSections[1];
+} KDBGMODDBGHELP, *PKDBGMODDBGHELP;
+
+
+/**
+ * Convers a Windows error to kDbg error code.
+ *
+ * @returns kDbg status code.
+ * @param   rc          The Windows error.
+ */
+static int kdbgModDHConvWinError(DWORD rc)
+{
+    switch (rc)
+    {
+        case 0:                     return 0;
+        default:                    return KERR_GENERAL_FAILURE;
+    }
+}
+
+
+/**
+ * Calcs the RVA for a segment:offset address.
+ *
+ * @returns IPRT status code.
+ *
+ * @param   pModDH      The PE debug module instance.
+ * @param   iSegment    The segment number. Special segments are dealt with as well.
+ * @param   off         The segment offset.
+ * @param   puRVA       Where to store the RVA on success.
+ */
+static int kdbgModDHSegOffToRVA(PKDBGMODDBGHELP pModDH, KI32 iSegment, KDBGADDR off, KU32 *puRVA)
+{
+    if (iSegment >= 0)
+    {
+        kDbgAssertMsgReturn(iSegment < pModDH->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModDH->cSections),
+                            KDBG_ERR_INVALID_ADDRESS);
+        kDbgAssertMsgReturn(off < pModDH->aSections[iSegment].Misc.VirtualSize,
+                            ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModDH->aSections[iSegment].Misc.VirtualSize),
+                            KDBG_ERR_INVALID_ADDRESS);
+        *puRVA = pModDH->aSections[iSegment].VirtualAddress + (KU32)off;
+        return 0;
+    }
+
+    if (iSegment == KDBGSEG_RVA)
+    {
+        kDbgAssertMsgReturn(off < pModDH->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModDH->cbImage),
+                            KDBG_ERR_INVALID_ADDRESS);
+        *puRVA = (KU32)off;
+        return 0;
+    }
+    kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS);
+}
+
+
+/**
+ * Calcs the segment:offset address for a RVA.
+ *
+ * @returns IPRT status code.
+ *
+ * @param   pModDH      The PE debug module instance.
+ * @param   uRVA        The RVA.
+ * @param   piSegment   Where to store the segment number.
+ * @param   poff        Where to store the segment offset.
+ */
+static int kdbgModDHRVAToSegOff(PKDBGMODDBGHELP pModDH, KU32 uRVA, KI32 *piSegment, KDBGADDR *poff)
+{
+    kDbgAssertMsgReturn(uRVA < pModDH->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModDH->cbImage),
+                        KDBG_ERR_INVALID_ADDRESS);
+    for (KI32 iSegment = 0; iSegment < pModDH->cSections; iSegment++)
+    {
+        /** @todo should probably be less strict about address in the alignment gaps. */
+        KU32 off = uRVA - pModDH->aSections[iSegment].VirtualAddress;
+        if (off < pModDH->aSections[iSegment].Misc.VirtualSize)
+        {
+            *poff = off;
+            *piSegment = iSegment;
+            return 0;
+        }
+    }
+    kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS);
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQueryLine
+ */
+static int kdbgModDHQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine)
+{
+    PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
+
+    /*
+     * Translate the address to an RVA.
+     */
+    KU32 uRVA;
+    int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA);
+    if (!rc)
+    {
+        DWORD64 off;
+        IMAGEHLP_LINE64 Line;
+        Line.SizeOfStruct = sizeof(Line);
+        if (g_pfnSymGetLineFromAddr64(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Line))
+        {
+            pLine->RVA = (KDBGADDR)(Line.Address - pModDH->ImageBase);
+            rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pLine->RVA, &pLine->iSegment, &pLine->offSegment);
+            pLine->iLine = Line.LineNumber;
+            KSIZE cchFile = kHlpStrLen(Line.FileName);
+            pLine->cchFile = cchFile < sizeof(pLine->szFile)
+                           ? (KU16)cchFile
+                           : (KU16)sizeof(pLine->szFile) - 1;
+            kHlpMemCopy(pLine->szFile, Line.FileName, pLine->cchFile);
+            pLine->szFile[pLine->cchFile] = '\0';
+        }
+        else
+        {
+            DWORD Err = GetLastError();
+            rc = kdbgModDHConvWinError(Err);
+        }
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQuerySymbol
+ */
+static int kdbgModDHQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
+{
+    PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
+
+    /*
+     * Translate the address to an RVA.
+     */
+    KU32 uRVA;
+    int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA);
+    if (!rc)
+    {
+        DWORD64 off;
+        union
+        {
+            SYMBOL_INFO Sym;
+            char        achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX];
+        } Buf;
+        Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
+        Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX;
+        if (g_pfnSymFromAddr(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Buf.Sym))
+        {
+            pSym->cb      = Buf.Sym.Size;
+            pSym->Address = NIL_KDBGADDR;
+            pSym->fFlags  = 0;
+            if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
+                pSym->fFlags |= KDBGSYM_FLAGS_CODE;
+            else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
+                pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
+            else
+                pSym->fFlags |= KDBGSYM_FLAGS_DATA;
+            if (Buf.Sym.Flags & SYMFLAG_EXPORT)
+                pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED;
+            if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
+            {
+                pSym->iSegment   = KDBGSEG_ABS;
+                pSym->offSegment = (KDBGADDR)Buf.Sym.Value;
+                pSym->RVA        = (KDBGADDR)Buf.Sym.Value;
+            }
+            else
+            {
+                pSym->RVA        = (KDBGADDR)(Buf.Sym.Address - pModDH->ImageBase);
+                rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pSym->RVA, &pSym->iSegment, &pSym->offSegment);
+            }
+            pSym->cchName = (KU16)Buf.Sym.NameLen;
+            if (pSym->cchName >= sizeof(pSym->szName))
+                pSym->cchName = sizeof(pSym->szName) - 1;
+            kHlpMemCopy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
+            pSym->szName[Buf.Sym.NameLen] = '\0';
+        }
+        else
+        {
+            DWORD Err = GetLastError();
+            rc = kdbgModDHConvWinError(Err);
+        }
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnClose
+ */
+static int kdbgModDHClose(PKDBGMOD pMod)
+{
+    PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
+
+    if (g_pfnSymCleanup(pModDH->hSymInst))
+        return 0;
+
+    DWORD Err = GetLastError();
+    int rc = kdbgModDHConvWinError(Err);
+    kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc));
+    return rc;
+}
+
+
+/**
+ * Checks if the specified dbghelp.dll is usable.
+ *
+ * @returns IPRT status code.
+ *
+ * @param   pszPath     the path to the dbghelp.dll.
+ */
+static int kdbgModDHTryDbgHelp(const char *pszPath, KU32 *pu32FileVersionMS, KU32 *pu32FileVersionLS)
+{
+    int rc;
+    DWORD dwHandle = 0;
+    DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle);
+    if (cb > 0)
+    {
+        void *pvBuf = alloca(cb);
+        if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf))
+        {
+            UINT cbValue = 0;
+            VS_FIXEDFILEINFO *pFileInfo;
+            if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue))
+            {
+                /** @todo somehow reject 64-bit .dlls when in 32-bit mode... dwFileOS is completely useless. */
+                if (    *pu32FileVersionMS < pFileInfo->dwFileVersionMS
+                    ||  (   *pu32FileVersionMS == pFileInfo->dwFileVersionMS
+                         && *pu32FileVersionLS  > pFileInfo->dwFileVersionLS))
+                {
+                    *pu32FileVersionMS = pFileInfo->dwFileVersionMS;
+                    *pu32FileVersionLS = pFileInfo->dwFileVersionLS;
+                }
+                if (pFileInfo->dwFileVersionMS >= 0x60004)
+                    rc = 0;
+                else
+                    rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH;
+            }
+            else
+                rc = KERR_GENERAL_FAILURE;
+        }
+        else
+            rc = kdbgModDHConvWinError(GetLastError());
+    }
+    else
+        rc = kdbgModDHConvWinError(GetLastError());
+    return rc;
+}
+
+
+/**
+ * Find the dbghelp.dll
+ */
+static int kdbgModDHFindDbgHelp(char *pszPath, KSIZE cchPath)
+{
+    /*
+     * Try the current directory.
+     */
+    KU32 FileVersionMS = 0;
+    KU32 FileVersionLS = 0;
+    int rc = KERR_GENERAL_FAILURE;
+    static char s_szDbgHelp[] = "\\dbghelp.dll";
+    if (GetCurrentDirectory((DWORD)(cchPath - sizeof(s_szDbgHelp) + 1), pszPath))
+    {
+        strcat(pszPath, s_szDbgHelp);
+        int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+        if (!rc2)
+            return rc2;
+        if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+            rc = rc2;
+    }
+
+    /*
+     * Try the application directory.
+     */
+    if (GetModuleFileName(NULL, pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
+    {
+        kHlpStrCat(kHlpStrRChr(pszPath, '\\'), s_szDbgHelp);
+        int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+        if (!rc)
+            return rc2;
+        if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+            rc = rc2;
+    }
+
+    /*
+     * Try the windows directory.
+     */
+    if (GetSystemDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
+    {
+        kHlpStrCat(pszPath, s_szDbgHelp);
+        int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+        if (!rc2)
+            return rc2;
+        if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+            rc = rc2;
+    }
+
+    /*
+     * Try the windows directory.
+     */
+    if (GetWindowsDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
+    {
+        kHlpStrCat(pszPath, s_szDbgHelp);
+        int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+        if (!rc2)
+            return rc2;
+        if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+            rc = rc2;
+    }
+
+    /*
+     * Try the path.
+     */
+    /** @todo find the actual path specs, I'm probably not doing this 100% correctly here. */
+    DWORD cb = GetEnvironmentVariable("PATH", NULL, 0) + 64;
+    char *pszSearchPath = (char *) alloca(cb);
+    if (GetEnvironmentVariable("PATH", pszSearchPath, cb) < cb)
+    {
+        char *psz = pszSearchPath;
+        while (*psz)
+        {
+            /* find the end of the path. */
+            char *pszEnd = kHlpStrChr(psz, ';');
+            if (!pszEnd)
+                pszEnd = kHlpStrChr(psz, '\0');
+            if (pszEnd != psz)
+            {
+                /* construct filename and try it out */
+                kHlpMemCopy(pszPath, psz, pszEnd - psz);
+                kHlpMemCopy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp));
+                int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+                if (!rc2)
+                    return rc2;
+                if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+                    rc = rc2;
+            }
+
+            /* next path */
+            if (!*pszEnd)
+                break;
+            psz = pszEnd + 1;
+        }
+    }
+
+    if (rc == KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+        kDbgAssertMsgFailed(("dbghelp.dll found, but it was ancient! The highest file version found was 0x%08x'%08x.\n"
+                             "This program require a file version of at least 0x00060004'00000000. Please download\n"
+                             "the latest windbg and use the dbghelp.dll from that package. Just put it somewhere in\n"
+                             "the PATH and we'll find it.\n", FileVersionMS, FileVersionLS));
+    else
+        kDbgAssertMsgFailed(("dbghelp.dll was not found! Download the latest windbg and use the dbghelp.dll\n"
+                             "from that package - just put it somewhere in the PATH and we'll find it.\n"));
+    return rc;
+}
+
+
+/**
+ * Loads the dbghelp.dll, check that it's the right version, and
+ * resolves all the symbols we need.
+ *
+ * @returns IPRT status code.
+ */
+static int kdbgModDHLoadDbgHelp(void)
+{
+    if (g_hDbgHelp)
+        return 0;
+
+    /* primitive locking - make some useful API for this kind of spinning! */
+    static volatile long s_lLock = 0;
+    while (InterlockedCompareExchange(&s_lLock, 1, 0))
+        while (s_lLock)
+            Sleep(1);
+    if (g_hDbgHelp)
+    {
+        InterlockedExchange(&s_lLock, 0);
+        return 0;
+    }
+
+    /*
+     * Load it - try current dir first.
+     */
+    char szPath[260];
+    int rc = kdbgModDHFindDbgHelp(szPath, sizeof(szPath));
+    if (rc)
+    {
+        InterlockedExchange(&s_lLock, 0);
+        return rc;
+    }
+
+    HMODULE hmod = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+    if (!hmod)
+    {
+        DWORD Err = GetLastError();
+        int rc = kdbgModDHConvWinError(Err);
+        InterlockedExchange(&s_lLock, 0);
+        kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%d\n", szPath, Err, rc), rc);
+    }
+
+    /*
+     * Check the API version (too).
+     */
+    LPAPI_VERSION (WINAPI *pfnImagehlpApiVersion)(VOID);
+    FARPROC *ppfn = (FARPROC *)&pfnImagehlpApiVersion;
+    *ppfn = GetProcAddress(hmod, "ImagehlpApiVersion");
+    if (*ppfn)
+    {
+        LPAPI_VERSION pVersion = pfnImagehlpApiVersion();
+        if (    pVersion
+            &&  (   pVersion->MajorVersion > 4
+                 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion > 0)
+                 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion == 0 && pVersion->Revision >= 5)
+                )
+           )
+        {
+            /*
+             * Resolve the entrypoints we need.
+             */
+            static const struct
+            {
+                const char *pszName;
+                FARPROC *ppfn;
+            }   s_aFunctions[] =
+            {
+                { "SymInitialize",      (FARPROC *)&g_pfnSymInitialize },
+                { "SymCleanup",         (FARPROC *)&g_pfnSymCleanup },
+                { "SymSetOptions",      (FARPROC *)&g_pfnSymSetOptions },
+                { "SymLoadModule64",    (FARPROC *)&g_pfnSymLoadModule64 },
+                { "SymFromAddr",        (FARPROC *)&g_pfnSymFromAddr },
+                { "SymFromAddr",        (FARPROC *)&g_pfnSymFromAddr },
+                { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 },
+            };
+            for (unsigned i = 0; i < K_ELEMENTS(s_aFunctions); i++)
+            {
+                FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName);
+                if (!pfn)
+                {
+                    DWORD Err = GetLastError();
+                    rc = kdbgModDHConvWinError(Err);
+                    kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%d\n",
+                                         s_aFunctions[i].pszName, Err, rc));
+                    break;
+                }
+                *s_aFunctions[i].ppfn = pfn;
+            }
+            if (!rc)
+            {
+                g_hDbgHelp = hmod;
+                Sleep(1);
+                InterlockedExchange(&s_lLock, 0);
+                return 0;
+            }
+        }
+        else
+        {
+            rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH;
+            kDbgAssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0));
+        }
+    }
+    else
+    {
+        DWORD Err = GetLastError();
+        rc = kdbgModDHConvWinError(Err);
+        kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%d\n", Err, rc));
+    }
+    FreeLibrary(hmod);
+    InterlockedExchange(&s_lLock, 0);
+    return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnOpen
+ */
+static int kdbgModDHOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
+{
+    /*
+     * This reader doesn't support partial files.
+     * Also weed out small files early on as they cannot be
+     * PE images and will only cause read errors
+     */
+    if (    off != 0
+        ||  cb != KFOFF_MAX)
+        return KDBG_ERR_UNKOWN_FORMAT;
+    if (kRdrSize(pRdr) < sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER))
+        return KDBG_ERR_UNKOWN_FORMAT;
+
+    /*
+     * We need to read the section headers and get the image size.
+     */
+    /* Find the PE header magic. */
+    KU32 offHdr = 0;
+    KU32 u32Magic;
+    int rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), 0);
+    kDbgAssertRCReturn(rc, rc);
+    if ((KU16)u32Magic == IMAGE_DOS_SIGNATURE)
+    {
+        rc = kRdrRead(pRdr, &offHdr, sizeof(offHdr), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew));
+        kDbgAssertRCReturn(rc, rc);
+        if (!offHdr)
+            return KDBG_ERR_FORMAT_NOT_SUPPORTED;
+        if (    offHdr < sizeof(IMAGE_DOS_SIGNATURE)
+            ||  offHdr >= kRdrSize(pRdr) - 4)
+            return KDBG_ERR_BAD_EXE_FORMAT;
+
+        rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), offHdr);
+        kDbgAssertRCReturn(rc, rc);
+    }
+    if (u32Magic != IMAGE_NT_SIGNATURE)
+        return KDBG_ERR_FORMAT_NOT_SUPPORTED;
+
+    /* read the file header and the image size in the optional header.. */
+    IMAGE_FILE_HEADER FHdr;
+    rc = kRdrRead(pRdr, &FHdr, sizeof(FHdr), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader));
+    kDbgAssertRCReturn(rc, rc);
+
+    KU32 cbImage;
+    if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
+        rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage),
+                      offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage));
+    else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
+        rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage),
+                      offHdr + K_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage));
+    else
+        kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT);
+    kDbgAssertRCReturn(rc, rc);
+
+    /*
+     * Load dbghelp.dll.
+     */
+    rc = kdbgModDHLoadDbgHelp();
+    if (rc)
+        return rc;
+
+    /*
+     * Allocate the module and read/construct the section headers.
+     */
+    PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)kHlpAlloc(K_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2]));
+    kDbgAssertReturn(pModDH, KERR_NO_MEMORY);
+    pModDH->Core.u32Magic   = KDBGMOD_MAGIC;
+    pModDH->Core.pOps       = &g_kDbgModWinDbgHelpOpen;
+    pModDH->Core.pRdr       = pRdr;
+    pModDH->Core.fCloseRdr  = fCloseRdr;
+    pModDH->Core.pLdrMod    = pLdrMod;
+    pModDH->cbImage         = cbImage;
+    pModDH->cSections       = 1 + FHdr.NumberOfSections;
+
+    rc = kRdrRead(pRdr, &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections,
+                  offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader);
+    if (!rc)
+    {
+        PIMAGE_SECTION_HEADER pSH = &pModDH->aSections[0];
+        kHlpMemCopy(pSH->Name, "headers", sizeof(pSH->Name));
+        pSH->Misc.VirtualSize       = pModDH->aSections[1].VirtualAddress;
+        pSH->VirtualAddress         = 0;
+        pSH->SizeOfRawData          = pSH->Misc.VirtualSize;
+        pSH->PointerToRawData       = 0;
+        pSH->PointerToRelocations   = 0;
+        pSH->PointerToLinenumbers   = 0;
+        pSH->NumberOfRelocations    = 0;
+        pSH->NumberOfLinenumbers    = 0;
+        pSH->Characteristics        = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
+
+        KU32 uTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress
+                     + pModDH->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
+        if (uTheEnd < cbImage)
+        {
+            pSH = &pModDH->aSections[pModDH->cSections++];
+            kHlpMemCopy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
+            pSH->Misc.VirtualSize       = cbImage - uTheEnd;
+            pSH->VirtualAddress         = uTheEnd;
+            pSH->SizeOfRawData          = pSH->Misc.VirtualSize;
+            pSH->PointerToRawData       = 0;
+            pSH->PointerToRelocations   = 0;
+            pSH->PointerToLinenumbers   = 0;
+            pSH->NumberOfRelocations    = 0;
+            pSH->NumberOfLinenumbers    = 0;
+            pSH->Characteristics        = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
+        }
+
+        /*
+         * Find a new dbghelp handle.
+         *
+         * We assume 4GB of handles outlast most debugging sessions, or in anyways that
+         * when we start reusing handles they are no longer in use. :-)
+         */
+        static volatile long s_u32LastHandle = 1;
+        HANDLE hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle);
+        while (     hSymInst == INVALID_HANDLE_VALUE
+               ||   hSymInst == (HANDLE)0
+               ||   hSymInst == GetCurrentProcess())
+            hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle);
+
+        /*
+         * Initialize dbghelp and try open the specified module.
+         */
+        if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
+        {
+            g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
+
+            KIPTR NativeFH = kRdrNativeFH(pRdr);
+            DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, NativeFH == -1 ? NULL : (HANDLE)NativeFH,
+                                                     kRdrName(pRdr), NULL, 0x00400000, 0);
+            if (ImageBase)
+            {
+                pModDH->hSymInst        = hSymInst;
+                pModDH->ImageBase       = ImageBase;
+                *ppMod = &pModDH->Core;
+                return rc;
+            }
+
+            DWORD Err = GetLastError();
+            rc = kdbgModDHConvWinError(Err);
+            kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%d\n", Err, rc));
+            g_pfnSymCleanup(hSymInst);
+        }
+        else
+        {
+            DWORD Err = GetLastError();
+            rc = kdbgModDHConvWinError(Err);
+            kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc));
+        }
+    }
+    else
+        kDbgAssertRC(rc);
+
+    kHlpFree(pModDH);
+    return rc;
+}
+
+
+/**
+ * Methods for a PE module.
+ */
+const KDBGMODOPS g_kDbgModWinDbgHelpOpen =
+{
+    "Windows DbgHelp",
+    NULL,
+    kdbgModDHOpen,
+    kdbgModDHClose,
+    kdbgModDHQuerySymbol,
+    kdbgModDHQueryLine,
+    "Windows DbgHelp"
+};
+
Index: /trunk/kDbg/kDbgModule.cpp
===================================================================
--- /trunk/kDbg/kDbgModule.cpp	(revision 2)
+++ /trunk/kDbg/kDbgModule.cpp	(revision 2)
@@ -0,0 +1,442 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, Module API.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kDbgInternal.h"
+#include <k/kHlpString.h>
+#include <k/kHlpAlloc.h>
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/**
+ * The built-in debug module readers.
+ */
+static PCKDBGMODOPS const g_aBuiltIns[] =
+{
+#if K_OS == K_OS_WINDOWS
+    &g_kDbgModWinDbgHelpOpen,
+#endif
+    &g_kDbgModLdr,
+//    &g_kDbgModCv8,
+//    &g_kDbgModDwarf,
+//    &g_kDbgModHll,
+//    &g_kDbgModStabs,
+//    &g_kDbgModSym,
+//    &g_kDbgModMapILink,
+//    &g_kDbgModMapMSLink,
+//    &g_kDbgModMapNm,
+//    &g_kDbgModMapWLink
+};
+
+/**
+ * The debug module readers registered at runtime.
+ */
+static PKDBGMODOPS g_pHead = NULL;
+
+
+/**
+ * Register a debug module reader with the kDbgModule component.
+ *
+ * Dynamically registered readers are kept in FIFO order, and external
+ * readers will be tried after the builtin ones.
+ *
+ * Like all other kDbg APIs serializing is left to the caller.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pOps is missing bits.
+ * @returns KERR_INVALID_PARAMETER if pOps is already in the list.
+ * @param   pOps        The reader method table, kDbg takes owner ship of
+ *                      this. This must be writeable as the pNext pointer
+ *                      will be update. It must also stick around for as
+ *                      long as kDbg is in use.
+ */
+KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps)
+{
+    /*
+     * Validate input.
+     */
+    kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER);
+    kDbgAssertPtrReturn(pOps->pszName, KERR_INVALID_POINTER);
+    kDbgAssertPtrReturn(pOps->pfnOpen, KERR_INVALID_POINTER);
+    kDbgAssertPtrReturn(pOps->pfnClose, KERR_INVALID_POINTER);
+    kDbgAssertPtrReturn(pOps->pfnQuerySymbol, KERR_INVALID_POINTER);
+    kDbgAssertPtrReturn(pOps->pfnQueryLine, KERR_INVALID_POINTER);
+    kDbgAssertPtrReturn(pOps->pszName2, KERR_INVALID_POINTER);
+    if (kHlpStrComp(pOps->pszName, pOps->pszName2))
+        return KERR_INVALID_PARAMETER;
+    kDbgAssertReturn(pOps->pNext == NULL, KERR_INVALID_PARAMETER);
+
+    /*
+     * Link it into the list.
+     */
+    if (!g_pHead)
+        g_pHead = pOps;
+    else
+    {
+        PKDBGMODOPS pPrev = g_pHead;
+        while (pPrev->pNext)
+            pPrev = pPrev->pNext;
+        kDbgAssertReturn(pPrev != pOps, KERR_INVALID_PARAMETER);
+        pPrev->pNext = pOps;
+    }
+    return 0;
+}
+
+
+/**
+ * Deregister a debug module reader previously registered using
+ * the kDbgModuleRegisterReader API.
+ *
+ * Deregistering a reader does not mean that non of its functions
+ * will be called after successful return, it only means that it
+ * will no longer be subjected to new module.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pOps isn't a valid pointer.
+ * @returns KERR_INVALID_PARAMETER if pOps wasn't registered.
+ * @param   pOps    The debug module method table to deregister.
+ */
+KDBG_DECL(int) kDbgModuleDeregisterReader(PKDBGMODOPS pOps)
+{
+    /*
+     * Validate the pointer.
+     */
+    kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER);
+
+    /*
+     * Find it in the list and unlink it.
+     */
+    if (g_pHead == pOps)
+        g_pHead = pOps->pNext;
+    else
+    {
+        PKDBGMODOPS pPrev = g_pHead;
+        while (pPrev && pPrev->pNext != pOps)
+            pPrev = pPrev->pNext;
+        if (!pPrev)
+            return KERR_INVALID_PARAMETER;
+        pPrev->pNext = pOps->pNext;
+    }
+    pOps->pNext = NULL;
+    return 0;
+}
+
+
+
+/**
+ * Worker for the kDbgModuleOpen* APIs.
+ *
+ * This will make sure the reader is buffered. I will also take care of
+ * closing the reader opened by kDbgModuleOpen on failure.
+ *
+ * @returns 0 on success. An appropriate kErrors status code on failure.
+ * @param   ppDbgMod        Where to store the new debug module reader instance.
+ * @param   pRdr            The file provider.
+ * @param   fCloseRdr       Whether pRdr should be close or not. This applies both
+ *                          to the failure path and to the success path, where it'll
+ *                          be close when the module is closed by kDbgModuleClose().
+ * @param   off             The offset into the file where the debug info is supposed
+ *                          to be found.
+ *                          This is 0 if the entire file is the subject.
+ * @param   cb              The size of the debug info part of the file.
+ *                          This is KFOFF_MAX if the entire file is the subject.
+ * @param   pLdrMod         An optional kLdrMod association.
+ */
+static int kdbgModuleOpenWorker(PPKDBGMOD ppDbgMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
+{
+    /*
+     * If the reader isn't buffered create a buffered wrapper for it.
+     */
+    int rc;
+    PKRDR pRdrWrapped = NULL;
+    if (!kRdrBufIsBuffered(pRdr))
+    {
+        rc = kRdrBufWrap(&pRdrWrapped, pRdr, fCloseRdr);
+        if (rc)
+        {
+            if (fCloseRdr)
+                kRdrClose(pRdr);
+            return rc;
+        }
+        pRdr = pRdrWrapped;
+    }
+
+    /*
+     * Walk the built-in table and the list of registered readers
+     * and let each of them have a go at the file. Stop and return
+     * on the first one returning successfully.
+     */
+    rc = KDBG_ERR_UNKOWN_FORMAT;
+    for (KSIZE i = 0; i < K_ELEMENTS(g_aBuiltIns); i++)
+        if (g_aBuiltIns[i]->pfnOpen)
+        {
+            int rc2 = g_aBuiltIns[i]->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod);
+            if (!rc2)
+                return 0;
+            if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT)
+                rc = rc2;
+        }
+
+    for (PKDBGMODOPS pCur = g_pHead; pCur; pCur = pCur->pNext)
+        if (pCur->pfnOpen)
+        {
+            int rc2 = pCur->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod);
+            if (!rc2)
+                return 0;
+            if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT)
+                rc = rc2;
+        }
+
+    if (pRdrWrapped)
+        kRdrClose(pRdrWrapped);
+    else if (fCloseRdr)
+        kRdrClose(pRdr);
+    return rc;
+}
+
+
+/**
+ * Opens a debug module reader for the specified file or file section
+ *
+ * @returns kStuff status code.
+ * @param   ppDbgMod            Where to store the debug module reader handle.
+ * @param   pRdr                The file reader.
+ * @param   off                 The offset of the file section. If the entire file, pass 0.
+ * @param   cb                  The size of the file section. If the entire file, pass KFOFF_MAX.
+ * @param   pLdrMod             Associated kLdr module that the kDbg component can use to
+ *                              verify and suplement the debug info found in the file specified
+ *                              by pszFilename. The module will be used by kDbg for as long as
+ *                              the returned kDbg module remains open.
+ *                              This is an optional parameter, pass NULL if no kLdr module at hand.
+ */
+KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
+{
+    /*
+     * Validate input.
+     */
+    kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER);
+    kDbgAssertPtrReturn(pRdr, KERR_INVALID_POINTER);
+    kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER);
+    kDbgAssertMsgReturn(off >= 0 && off < KFOFF_MAX, (KFOFF_PRI "\n", off), KERR_INVALID_OFFSET);
+    kDbgAssertMsgReturn(cb >= 0 && cb <= KFOFF_MAX, (KFOFF_PRI "\n", cb), KERR_INVALID_SIZE);
+    kDbgAssertMsgReturn(off + cb > off, ("off=" KFOFF_PRI " cb=" KFOFF_PRI "\n", off, cb), KERR_INVALID_RANGE);
+    *ppDbgMod = NULL;
+
+    /*
+     * Hand it over to the internal worker.
+     */
+    return kdbgModuleOpenWorker(ppDbgMod, pRdr, K_FALSE /* fCloseRdr */, off, cb, pLdrMod);
+}
+
+
+/**
+ * Opens a debug module reader for the specified file.
+ *
+ * @returns kStuff status code.
+ * @param   ppDbgMod            Where to store the debug module reader handle.
+ * @param   pRdr                The file reader.
+ * @param   pLdrMod             Associated kLdr module that the kDbg component can use to
+ *                              verify and suplement the debug info found in the file specified
+ *                              by pszFilename. The module will be used by kDbg for as long as
+ *                              the returned kDbg module remains open.
+ *                              This is an optional parameter, pass NULL if no kLdr module at hand.
+ */
+KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod)
+{
+    return kDbgModuleOpenFilePart(ppDbgMod, pRdr, 0, KFOFF_MAX, pLdrMod);
+}
+
+
+/**
+ * Opens the debug info for a specified executable module.
+ *
+ * @returns kStuff status code.
+ * @param   ppDbgMod            Where to store the debug module handle.
+ * @param   pszFilename         The name of the file containing debug info and/or which
+ *                              debug info is wanted.
+ * @param   pLdrMod             Associated kLdr module that the kDbg component can use to
+ *                              verify and suplement the debug info found in the file specified
+ *                              by pszFilename. The module will be used by kDbg for as long as
+ *                              the returned kDbg module remains open.
+ *                              This is an optional parameter, pass NULL if no kLdr module at hand.
+ */
+KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod)
+{
+    /*
+     * Validate input.
+     */
+    kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER);
+    kDbgAssertPtrReturn(pszFilename, KERR_INVALID_POINTER);
+    kDbgAssertMsgReturn(*pszFilename, ("%p\n", pszFilename), KERR_INVALID_PARAMETER);
+    kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER);
+    *ppDbgMod = NULL;
+
+    /*
+     * Open the file and see if we can read it.
+     */
+    PKRDR pRdr;
+    int rc = kRdrBufOpen(&pRdr, pszFilename);
+    if (rc)
+        return rc;
+    rc = kdbgModuleOpenWorker(ppDbgMod, pRdr, K_TRUE /* fCloseRdr */, 0, KFOFF_MAX, pLdrMod);
+    return rc;
+}
+
+
+/**
+ * Closes the module.
+ *
+ * @returns IPRT status code.
+ * @param   pMod        The module handle.
+ */
+KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod)
+{
+    KDBGMOD_VALIDATE(pMod);
+    int rc = pMod->pOps->pfnClose(pMod);
+    if (!rc)
+    {
+        pMod->u32Magic++;
+        kHlpFree(pMod);
+    }
+    return rc;
+}
+
+
+/**
+ * Gets a symbol by segment:offset.
+ * This will be approximated to the nearest symbol if there is no exact match.
+ *
+ * @returns IPRT status code.
+ * @param   pMod        The module.
+ * @param   iSegment    The segment this offset is relative to.
+ *                      The -1 segment is special, it means that the addres is relative to
+ *                      the image base. The image base is where the first bit of the image
+ *                      is mapped during load.
+ * @param   off         The offset into the segment.
+ * @param   pSym        Where to store the symbol details.
+ */
+KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
+{
+    KDBGMOD_VALIDATE(pMod);
+    kDbgAssertPtrReturn(pSym, KERR_INVALID_POINTER);
+    return pMod->pOps->pfnQuerySymbol(pMod, iSegment, off, pSym);
+}
+
+
+/**
+ * Gets & allocates a symbol by segment:offset.
+ * This will be approximated to the nearest symbol if there is no exact match.
+ *
+ * @returns IPRT status code.
+ * @param   pMod        The module.
+ * @param   iSegment    The segment this offset is relative to.
+ *                      The -1 segment is special, it means that the addres is relative to
+ *                      the image base. The image base is where the first bit of the image
+ *                      is mapped during load.
+ * @param   off         The offset into the segment.
+ * @param   ppSym       Where to store the pointer to the symbol info.
+ *                      Free the returned symbol using kDbgSymbolFree().
+ */
+KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym)
+{
+    kDbgAssertPtrReturn(ppSym, KERR_INVALID_POINTER);
+
+    KDBGSYMBOL Sym;
+    int rc = kDbgModuleQuerySymbol(pMod, iSegment, off, &Sym);
+    if (!rc)
+    {
+        *ppSym = kDbgSymbolDup(&Sym);
+        if (!*ppSym)
+            rc = KERR_NO_MEMORY;
+    }
+    else
+        *ppSym = NULL;
+    return rc;
+}
+
+
+/**
+ * Gets a line number entry by segment:offset.
+ * This will be approximated to the nearest line number there is no exact match.
+ *
+ * @returns IPRT status code.
+ * @param   pMod        The module.
+ * @param   iSegment    The segment this offset is relative to.
+ *                      The -1 segment is special, it means that the addres is relative to
+ *                      the image base. The image base is where the first bit of the image
+ *                      is mapped during load.
+ * @param   off         The offset into the segment.
+ * @param   pLine       Where to store the line number details.
+ */
+KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine)
+{
+    KDBGMOD_VALIDATE(pMod);
+    kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER);
+    return pMod->pOps->pfnQueryLine(pMod, iSegment, off, pLine);
+}
+
+
+/**
+ * Gets & allocates a line number entry by segment:offset.
+ * This will be approximated to the nearest line number there is no exact match.
+ *
+ * @returns IPRT status code.
+ * @param   pMod        The module.
+ * @param   iSegment    The segment this offset is relative to.
+ *                      The -1 segment is special, it means that the addres is relative to
+ *                      the image base. The image base is where the first bit of the image
+ *                      is mapped during load.
+ * @param   off         The offset into the segment.
+ * @param   ppLine      Where to store the pointer to the line number info.
+ *                      Free the returned line number using kDbgLineFree().
+ */
+KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine)
+{
+    kDbgAssertPtrReturn(ppLine, KERR_INVALID_POINTER);
+
+    KDBGLINE Line;
+    int rc = kDbgModuleQueryLine(pMod, iSegment, off, &Line);
+    if (!rc)
+    {
+        *ppLine = kDbgLineDup(&Line);
+        if (!*ppLine)
+            rc = KERR_NO_MEMORY;
+    }
+    else
+        *ppLine = NULL;
+    return rc;
+}
+
Index: /trunk/kDbg/kDbgSpace.cpp
===================================================================
--- /trunk/kDbg/kDbgSpace.cpp	(revision 2)
+++ /trunk/kDbg/kDbgSpace.cpp	(revision 2)
@@ -0,0 +1,194 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, Address Space Manager.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+#include <k/kAvl.h>
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/** Pointer to a name space module. */
+typedef struct KDBGSPACEMOD *PKDBGSPACEMOD;
+
+/**
+ * Tracks a module segment in the address space.
+ *
+ * These segments are organized in two trees, by address in the
+ * KDBGSPACE::pSegRoot tree and by selector value in the
+ * KDBGSPACE::pSegSelRoot tree.
+ *
+ * While the debug module reader could easily provide us with
+ * segment names and it could perhaps be interesting to lookup
+ * a segment by its name in some situations, this has been
+ * considered too much bother for now. :-)
+ */
+typedef struct KDBGSPACESEG
+{
+    /** The module segment index. */
+    KI32                    iSegment;
+    /** The address space module structure this segment belongs to. */
+    PKDBGSPACEMOD           pSpaceMod;
+} KDBGSPACESEG;
+typedef KDBGSPACESEG *PKDBGSPACESEG;
+
+
+/**
+ * Track a module in the name space.
+ *
+ * Each module in the address space can be addressed efficiently
+ * by module name. The module name has to be unique.
+ */
+typedef struct KDBGSPACEMOD
+{
+    /** The module name hash. */
+    KU32                    u32Hash;
+    /** The length of the module name. */
+    KU32                    cchName;
+    /** The module name. */
+    char                   *pszName;
+    /** The next module in the same bucket. */
+    PKDBGSPACEMOD           pNext;
+    /** Pointer to the debug module reader. */
+    PKDBGMOD                pMod;
+    /** The number of segments. */
+    KU32                    cSegs;
+    /** The segment array. (variable length) */
+    KDBGSPACESEG            aSegs[1];
+} KDBGSPACEMOD;
+
+
+typedef struct KDBGCACHEDSYM *PKDBGCACHEDSYM;
+/**
+ * A cached symbol.
+ */
+typedef struct KDBGCACHEDSYM
+{
+    /** The symbol name hash. */
+    KU32                    u32Hash;
+    /** The next symbol in the same bucket. */
+    PKDBGCACHEDSYM          pNext;
+    /** The next symbol belonging to the same module as this. */
+    PKDBGCACHEDSYM          pNextMod;
+    /** The cached symbol information. */
+    KDBGSYMBOL              Sym;
+} KDBGCACHEDSYM;
+
+
+/**
+ * A symbol cache.
+ */
+typedef struct KDBGSYMCACHE
+{
+    /** The symbol cache magic. (KDBGSYMCACHE_MAGIC) */
+    KU32                    u32Magic;
+    /** The maximum number of symbols.*/
+    KU32                    cMax;
+    /** The current number of symbols.*/
+    KU32                    cCur;
+    /** The number of hash buckets. */
+    KU32                    cBuckets;
+    /** The address lookup tree. */
+    PKDBGADDRAVL            pAddrTree;
+    /** Array of hash buckets.
+     * The size is selected according to the cache size. */
+    PKDBGCACHEDSYM         *paBuckets[1];
+} KDBGSYMCACHE;
+typedef KDBGSYMCACHE *PKDBGSYMCACHE;
+
+
+/**
+ * A user symbol record.
+ *
+ * The user symbols are organized in the KDBGSPACE::pUserRoot tree
+ * and form an overlay that overrides the debug info retrieved from
+ * the KDBGSPACE::pSegRoot tree.
+ *
+ * In the current implementation the user symbols are unique and
+ * one would have to first delete a symbol in order to add another
+ * at the same address. This may be changed later, perhaps.
+ */
+typedef struct KDBGSPACEUSERSYM
+{
+
+} KDBGSPACEUSERSYM;
+typedef KDBGSPACEUSERSYM *PKDBGSPACEUSERSYM;
+
+
+
+/**
+ * Address space.
+ */
+typedef struct KDBGSPACE
+{
+    /** The addresspace magic. (KDBGSPACE_MAGIC) */
+    KU32            u32Magic;
+    /** User defined address space identifier or data pointer. */
+    KUPTR           uUser;
+    /** The name of the address space. (Optional) */
+    const char     *pszName;
+
+
+} KDBGSPACE;
+/** Pointer to an address space. */
+typedef struct KDBGSPACE *PKDBGSPACE;
+/** Pointer to an address space pointer. */
+typedef PKDBGSPACE *PPKDBGSPACE;
+
+
+KDBG_DECL(int) kDbgSpaceCreate(PPDBGSPACE ppSpace, KDBGADDR LowAddr, DBGADDR HighAddr,
+                               KUPTR uUser, const char *pszName)
+{
+    /*
+     * Validate input.
+     */
+    kDbgAssertPtrReturn(ppSpace);
+    *ppSpace = NULL;
+    kDbgAssertPtrNullReturn(pszName);
+    kDbgAssertReturn(LowAddr < HighAddr);
+
+    /*
+     * Create and initialize the address space.
+     */
+    PKDBGSPACE pSpace = (PKDBGSPACE)kHlpAlloc(sizeof(*pSpace));
+    if (!pSpace)
+        return KERR_NO_MEMORY;
+    pSpace->u32Magic = KDBGSPACE_MAGIC;
+    pSpace->uUser = uUser;
+    pSpace->pszName = pszName;
+
+}
Index: /trunk/kDbg/kDbgSymbol.cpp
===================================================================
--- /trunk/kDbg/kDbgSymbol.cpp	(revision 2)
+++ /trunk/kDbg/kDbgSymbol.cpp	(revision 2)
@@ -0,0 +1,80 @@
+/* $Id$ */
+/** @file
+ * kDbg - The Debug Info Reader, Symbols.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+
+
+/**
+ * Duplicates a symbol.
+ *
+ * To save heap space, the returned symbol will not own more heap space than
+ * it strictly need to. So, it's not possible to append stuff to the symbol
+ * or anything of that kind.
+ *
+ * @returns Pointer to the duplicate.
+ *          This must be freed using kDbgSymbolFree().
+ * @param   pSymbol     The symbol to be duplicated.
+ */
+KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol)
+{
+    kDbgAssertPtrReturn(pSymbol, NULL);
+    KSIZE cb = K_OFFSETOF(KDBGSYMBOL, szName[pSymbol->cchName + 1]);
+    PKDBGSYMBOL pNewSymbol = (PKDBGSYMBOL)kHlpDup(pSymbol, cb);
+    if (pNewSymbol)
+        pNewSymbol->cbSelf = cb;
+    return pNewSymbol;
+}
+
+
+/**
+ * Frees a symbol obtained from the kDbg API.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pSymbol isn't a valid pointer.
+ *
+ * @param   pSymbol     The symbol to be freed. The null pointer is ignored.
+ */
+KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol)
+{
+    if (!pSymbol)
+    {
+        kDbgAssertPtrReturn(pSymbol, KERR_INVALID_POINTER);
+        pSymbol->cbSelf = 0;
+        kHlpFree(pSymbol);
+    }
+    return 0;
+}
+
Index: /trunk/kErr/Makefile.kmk
===================================================================
--- /trunk/kErr/Makefile.kmk	(revision 2)
+++ /trunk/kErr/Makefile.kmk	(revision 2)
@@ -0,0 +1,57 @@
+# $Id$
+## @file
+# kErr - The Status Code API, sub-makefile.
+#
+
+#
+# Copyright (c) 2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kStuff 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+DEPTH ?= ../..
+SUB_DEPTH ?= ..
+include $(PATH_KBUILD)/subheader.kmk
+
+#
+# kHlpBaseStatic
+#
+LIBRARIES += kErrStatic
+kErrStatic_TEMPLATE = kStuffLIB
+kErrStatic_SOURCES = \
+	kErrName.c
+
+kErrName.c_DEPS = $(PATH_TARGET)/kErrNameConsts.h
+kErrName.c_INCS = $(PATH_TARGET)
+
+#
+# Generate case statements for kErrName().
+#
+$(PATH_TARGET)/kErrNameConsts.h: $(PATH_SUB_ROOT)/include/k/kErrors.h $(MAKEFILE_CURRENT) | $(call DIRDEP,$(PATH_TARGET))
+	$(RM) -f $@
+	$(SED) \
+		-e '/^#define  *\(K[A-Z_]*ERR_[^ ()]*\) .*$$/!d' \
+		-e 's/^#define  *\(K[A-Z_]*ERR_[^ ()]*\) .*$$/ERR_CONST(\1)/' \
+		-e '/K[A-Z_]*ERR_[A-Z0-9_]*BASE/d' \
+		-e '/K[A-Z_]*ERR_[A-Z0-9_]*END/d' \
+		$< > $@
+
+
+# Generate the rules
+include $(PATH_KBUILD)/subfooter.kmk
+
Index: /trunk/kErr/kErrName.c
===================================================================
--- /trunk/kErr/kErrName.c	(revision 2)
+++ /trunk/kErr/kErrName.c	(revision 2)
@@ -0,0 +1,59 @@
+/* $Id$ */
+/** @file
+ * kErr - Status Code API, kErrName.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kErr.h>
+#include <k/kErrors.h>
+
+
+/**
+ * Translate the error code into a string containing
+ * the error constant.
+ *
+ * @returns Read only string with the constant name.
+ * @param   rc      The kErrors status code.
+ */
+KERR_DECL(const char *) kErrName(int rc)
+{
+    switch (rc)
+    {
+        case 0: return "SUCCESS";
+#define ERR_CONST(c) case c: return #c;
+#include "kErrNameConsts.h"
+#undef ERR_CONST
+        default:
+            return "KERR_UNKNOWN_ERROR";
+    }
+}
+
Index: /trunk/kHlp/Bare/kHlpBare-gcc.c
===================================================================
--- /trunk/kHlp/Bare/kHlpBare-gcc.c	(revision 2)
+++ /trunk/kHlp/Bare/kHlpBare-gcc.c	(revision 2)
@@ -0,0 +1,225 @@
+/* $Id$ */
+/** @file
+ * kHlpBare - The Dynamic Loader, Helper Functions for GCC.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include <k/kLdr.h>
+#include "kHlp.h"
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+
+
+void *memchr(const void *pv, int ch, KSIZE cb)
+{
+    const char *pb = pv;
+    while (cb-- > 0)
+    {
+        if (*pb == ch)
+            return (void *)pb;
+        pb++;
+    }
+    return 0;
+}
+
+
+int memcmp(const void *pv1, const void *pv2, KSIZE cb)
+{
+    /*
+     * Pointer size pointer size.
+     */
+    if (    cb > 16
+        &&  !((KUPTR)pv1 & (sizeof(void *) - 1))
+        &&  !((KUPTR)pv2 & (sizeof(void *) - 1)) )
+    {
+        const KUPTR *pu1 = pv1;
+        const KUPTR *pu2 = pv2;
+        while (cb >= sizeof(KUPTR))
+        {
+            const KUPTR u1 = *pu1++;
+            const KUPTR u2 = *pu2++;
+            if (u1 != u2)
+                return u1 > u2 ? 1 : -1;
+            cb -= sizeof(KUPTR);
+        }
+        if (!cb)
+            return 0;
+        pv1 = (const void *)pu1;
+        pv2 = (const void *)pu2;
+    }
+
+    /*
+     * Byte by byte.
+     */
+    if (cb)
+    {
+        const unsigned char *pb1 = pv1;
+        const unsigned char *pb2 = pv2;
+        while (cb-- > 0)
+        {
+            const unsigned char b1 = *pb1++;
+            const unsigned char b2 = *pb2++;
+            if (b1 != b2)
+                return b1 > b2 ? 1 : -1;
+        }
+    }
+    return 0;
+}
+
+
+void *memcpy(void *pv1, const void *pv2, KSIZE cb)
+{
+    void *pv1Start = pv1;
+
+    /*
+     * Pointer size pointer size.
+     */
+    if (    cb > 16
+        &&  !((KUPTR)pv1 & (sizeof(void *) - 1))
+        &&  !((KUPTR)pv2 & (sizeof(void *) - 1)) )
+    {
+        KUPTR       *pu1 = pv1;
+        const KUPTR *pu2 = pv2;
+        while (cb >= sizeof(KUPTR))
+        {
+            cb -= sizeof(KUPTR);
+            *pu1++ = *pu2++;
+        }
+        if (!cb)
+            return 0;
+        pv1 = (void *)pu1;
+        pv2 = (const void *)pu2;
+    }
+
+    /*
+     * byte by byte
+     */
+    if (cb)
+    {
+        unsigned char       *pb1 = pv1;
+        const unsigned char *pb2 = pv2;
+        while (cb-- > 0)
+            *pb1++ = *pb2++;
+    }
+
+    return pv1Start;
+}
+
+void *memset(void *pv, int ch, KSIZE cb)
+{
+    void *pvStart = pv;
+
+    /*
+     * Pointer size pointer size.
+     */
+    if (    cb > 16
+        &&  !((KUPTR)pv & (sizeof(void *) - 1)))
+    {
+        KUPTR  *pu = pv;
+        KUPTR   u = ch | (ch << 8);
+        u |= u << 16;
+#if K_ARCH_BITS >= 64
+        u |= u << 32;
+#endif
+#if K_ARCH_BITS >= 128
+        u |= u << 64;
+#endif
+
+        while (cb >= sizeof(KUPTR))
+        {
+            cb -= sizeof(KUPTR);
+            *pu++ = u;
+        }
+    }
+
+    /*
+     * Byte by byte
+     */
+    if (cb)
+    {
+        unsigned char *pb = pv;
+        while (cb-- > 0)
+            *pb++ = ch;
+    }
+    return pvStart;
+}
+
+
+int strcmp(const char *psz1, const char *psz2)
+{
+    for (;;)
+    {
+        const char ch1 = *psz1++;
+        const char ch2 = *psz2++;
+        if (ch1 != ch2)
+            return (int)ch1 - (int)ch2;
+        if (!ch1)
+            return 0;
+    }
+}
+
+
+int strncmp(const char *psz1, const char *psz2, KSIZE cch)
+{
+    while (cch-- > 0)
+    {
+        const char ch1 = *psz1++;
+        const char ch2 = *psz2++;
+        if (ch1 != ch2)
+            return (int)ch1 - (int)ch2;
+        if (!ch1)
+            break;
+    }
+    return 0;
+}
+
+char *strchr(const char *psz, int ch)
+{
+    for (;;)
+    {
+        const char chCur = *psz;
+        if (chCur == ch)
+            return (char *)psz;
+        if (!chCur)
+            return 0;
+        psz++;
+    }
+}
+
+KSIZE strlen(const char *psz)
+{
+    const char *pszStart = psz;
+    while (*psz)
+        psz++;
+    return psz - pszStart;
+}
+
Index: /trunk/kHlp/Bare/kHlpBareAssert.c
===================================================================
--- /trunk/kHlp/Bare/kHlpBareAssert.c	(revision 2)
+++ /trunk/kHlp/Bare/kHlpBareAssert.c	(revision 2)
@@ -0,0 +1,140 @@
+/* $Id$ */
+/** @file
+ * kHlpBare - Assert Backend.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpAssert.h>
+#include <k/kHlpString.h>
+
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+# include <k/kHlpSys.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif  K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#else
+# error "port me"
+#endif
+
+
+/**
+ * Writes a assert string with unix lineendings.
+ *
+ * @param   pszMsg  The string.
+ */
+static void kHlpAssertWrite(const char *pszMsg)
+{
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    KSIZE cchMsg = kHlpStrLen(pszMsg);
+    kHlpSys_write(2 /* stderr */, pszMsg, cchMsg);
+
+#elif K_OS == K_OS_OS2 ||  K_OS == K_OS_WINDOWS
+    /*
+     * Line by line.
+     */
+    ULONG       cbWritten;
+    const char *pszNl = kHlpStrChr(pszMsg, '\n');
+    while (pszNl)
+    {
+        cbWritten = pszNl - pszMsg;
+
+#if K_OS == K_OS_OS2
+        if (cbWritten)
+            DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten);
+        DosWrite((HFILE)2, "\r\n", 2, &cbWritten);
+#else /* K_OS == K_OS_WINDOWS */
+        if (cbWritten)
+            WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL);
+        WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL);
+#endif
+
+        /* next */
+        pszMsg = pszNl + 1;
+        pszNl = kHlpStrChr(pszMsg, '\n');
+    }
+
+    /*
+     * Remaining incomplete line.
+     */
+    if (*pszMsg)
+    {
+        cbWritten = kHlpStrLen(pszMsg);
+#if K_OS == K_OS_OS2
+        DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten);
+#else /* K_OS == K_OS_WINDOWS */
+        WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL);
+#endif
+    }
+
+#else
+# error "port me"
+#endif
+}
+
+
+KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction)
+{
+    char szLine[16];
+
+    kHlpAssertWrite("\n!!!kLdr Assertion Failed!!!\nExpression: ");
+    kHlpAssertWrite(pszExpr);
+    kHlpAssertWrite("\nAt: ");
+    kHlpAssertWrite(pszFile);
+    kHlpAssertWrite("(");
+    kHlpAssertWrite(kHlpInt2Ascii(szLine, sizeof(szLine), iLine, 10));
+    kHlpAssertWrite(") ");
+    kHlpAssertWrite(pszFunction);
+    kHlpAssertWrite("\n");
+}
+
+
+KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...)
+{
+    kHlpAssertWrite(pszFormat);
+}
+
Index: /trunk/kHlp/Bare/kHlpBareEnv.c
===================================================================
--- /trunk/kHlp/Bare/kHlpBareEnv.c	(revision 2)
+++ /trunk/kHlp/Bare/kHlpBareEnv.c	(revision 2)
@@ -0,0 +1,104 @@
+/* $Id$ */
+/** @file
+ * kHlpBare - Environment Manipulation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpEnv.h>
+#include <k/kHlpString.h>
+#include <k/kErrors.h>
+
+#if K_OS == K_OS_DARWIN
+
+#elif K_OS == K_OS_LINUX
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif  K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#else
+# error "port me"
+#endif
+
+
+KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal)
+{
+#if K_OS == K_OS_DARWIN
+    /** @todo need to figure out where the stuff is or how it's inherited on darwin ... */
+    return KERR_ENVVAR_NOT_FOUND;
+
+#elif K_OS == K_OS_LINUX
+    /** @todo either read /proc/self/environ or figure out where in the memory the initial environment is... */
+    return KERR_ENVVAR_NOT_FOUND;
+
+#elif K_OS == K_OS_OS2
+    PSZ pszValue = NULL;
+    int rc;
+
+    *pszVal = '\0';
+    rc = DosScanEnv((PCSZ)pszVar, &pszValue);
+    if (!rc)
+    {
+        KSIZE  cch = kHlpStrLen((const char *)pszValue);
+        if (cchVal > cch)
+            kHlpMemCopy(pszVal, pszValue, cch + 1);
+        else
+            rc = KERR_BUFFER_OVERFLOW;
+    }
+    else
+        rc = KERR_ENVVAR_NOT_FOUND;
+    return rc;
+
+#elif K_OS == K_OS_WINDOWS
+    DWORD cch;
+
+    SetLastError(0);
+    cch = GetEnvironmentVariable(pszVar, pszVal, cchVal);
+    if (cch > 0 && cch < cchVal)
+        return 0;
+
+    *pszVal = '\0';
+    if (cch >= cchVal)
+        return KERR_BUFFER_OVERFLOW;
+    if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
+        return KERR_ENVVAR_NOT_FOUND;
+    return GetLastError();
+
+#else
+# error "Port me"
+#endif
+}
+
Index: /trunk/kHlp/Bare/kHlpBareHeap.c
===================================================================
--- /trunk/kHlp/Bare/kHlpBareHeap.c	(revision 2)
+++ /trunk/kHlp/Bare/kHlpBareHeap.c	(revision 2)
@@ -0,0 +1,765 @@
+/* $Id$ */
+/** @file
+ * kHlpBare - Heap.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#define KHLPHEAP_STRICT
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+#include <k/kHlpAssert.h>
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif  K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#else
+# include <k/kHlpAlloc.h>
+#endif
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * A heap block.
+ */
+typedef struct KHLPHEAPBLOCK
+{
+    /** Next block in the global list. */
+    struct KHLPHEAPBLOCK   *pNext;
+    /** Previous block in the global list. */
+    struct KHLPHEAPBLOCK   *pPrev;
+    /** The size of this block including this header. */
+    KSIZE                   cb;
+    /** The flags. */
+    KSIZE                   fFlags;
+} KHLPHEAPBLOCK, *PKHLPHEAPBLOCK;
+
+/** Indicates whether the block is free (set) or allocated (clear). */
+#define KHLPHEAPBLOCK_FLAG_FREE     ((KSIZE)1)
+/** Valid flag mask. */
+#define KHLPHEAPBLOCK_FLAG_MASK     ((KSIZE)1)
+
+/** Checks if the block is freed. */
+#define KHLPHEAPBLOCK_IS_FREE(pB)       ( (pB)->fFlags & KHLPHEAPBLOCK_FLAG_FREE )
+/** Check if the block is allocated. */
+#define KHLPHEAPBLOCK_IS_ALLOCATED(pB)  !KHLPHEAPBLOCK_IS_FREE(pB)
+/** Checks if the two blocks are adjacent.
+ * Assumes pB1 < pB2. */
+#define KHLPHEAPBLOCK_IS_ADJACENT(pB1, pB2) \
+    ( ((KUPTR)(pB1) + (pB1)->cb) == (KUPTR)(pB2) )
+
+/** The block alignment. */
+#define KHLPHEAPBLOCK_ALIGNMENT     sizeof(KHLPHEAPBLOCK)
+
+/** @def KHLPHEAP_ASSERT
+ * Heap assertion. */
+/** @def KHLPHEAP_ASSERT_BLOCK
+ * Assert that a heap block is valid. */
+/** @def KHLPHEAP_ASSERT_FREE
+ * Assert that a heap free block is valid. */
+#ifdef KHLPHEAP_STRICT
+# define KHLPHEAP_ASSERT(expr)      kHlpAssert(expr)
+
+# define KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock) \
+    do { \
+        KHLPHEAP_ASSERT(!((pBlock)->fFlags & ~KHLPHEAPBLOCK_FLAG_MASK)); \
+        KHLPHEAP_ASSERT(!((pBlock)->cb & (KHLPHEAPBLOCK_ALIGNMENT - 1))); \
+        KHLPHEAP_ASSERT((KUPTR)(pBlock)->pPrev < (KUPTR)(pBlock)); \
+        KHLPHEAP_ASSERT((KUPTR)(pBlock)->pNext > (KUPTR)(pBlock) || !(pBlock)->pNext); \
+    } while (0)
+
+# define KHLPHEAP_ASSERT_FREE(pHeap, pFree) \
+    do { \
+        KHLPHEAP_ASSERT_BLOCK(pHeap, &(pFree)->Core); \
+        KHLPHEAP_ASSERT((KUPTR)(pFree)->pPrev < (KUPTR)(pFree)); \
+        KHLPHEAP_ASSERT((KUPTR)(pFree)->pNext > (KUPTR)(pFree) || !(pFree)->pNext); \
+    } while (0)
+
+#else
+# define KHLPHEAP_ASSERT(expr)          do { } while (0)
+# define KHLPHEAP_ASSERT_BLOCK(pH, pB)  do { } while (0)
+# define KHLPHEAP_ASSERT_FREE(pH, pF)   do { } while (0)
+#endif
+
+
+/**
+ * A free heap block.
+ */
+typedef struct KHLPHEAPFREE
+{
+    /** The core bit which we have in common with used blocks. */
+    KHLPHEAPBLOCK           Core;
+    /** The next free block. */
+    struct KHLPHEAPFREE    *pNext;
+    /** The previous free block. */
+    struct KHLPHEAPFREE    *pPrev;
+} KHLPHEAPFREE, *PKHLPHEAPFREE;
+
+
+/**
+ * A heap segment.
+ */
+typedef struct KHLPHEAPSEG
+{
+    /** The base address of the segment. */
+    void                   *pvBase;
+    /** The length of the segment (in bytes). */
+    KSIZE                   cb;
+} KHLPHEAPSEG, *PKHLPHEAPSEG;
+
+/**
+ * Bundle of heap segments.
+ */
+typedef struct KHLPHEAPSEGS
+{
+    /** Pointer to the next segment bundle. */
+    struct KHLPHEAPSEGS    *pNext;
+    /** The number of segments used. */
+    KU32                    cSegs;
+    /** Array of chunks. */
+    KHLPHEAPSEG             aSegs[64];
+} KHLPHEAPSEGS, *PKHLPHEAPSEGS;
+
+
+/**
+ * Heap anchor block.
+ */
+typedef struct KHLPHEAPANCHOR
+{
+    /** Head of the block list. */
+    PKHLPHEAPBLOCK          pHead;
+    /** Tail of the block list. */
+    PKHLPHEAPBLOCK          pTail;
+    /** Head of the free list. */
+    PKHLPHEAPFREE           pFreeHead;
+    /** Head segment bundle.
+     * The order of this list is important, but a bit peculiar.
+     * Logically, SegsHead::pNext is the tail pointer. */
+    KHLPHEAPSEGS            SegsHead;
+} KHLPHEAPANCHOR, *PKHLPHEAPANCHOR;
+
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The heap anchor block. */
+static KHLPHEAPANCHOR       g_Heap;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static int      khlpHeapInit(PKHLPHEAPANCHOR pHeap);
+static void     khlpHeapDelete(PKHLPHEAPANCHOR pHeap);
+static void *   khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb);
+static void     khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv);
+static KSIZE    khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv);
+static void     khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb);
+static int      khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cb);
+static void     khlpHeapSegFree(PKHLPHEAPSEG pSeg);
+
+
+/**
+ * Initializes the kLdr heap.
+ *
+ * @returns 0 on success, non-zero OS specific status code on failure.
+ */
+KHLP_DECL(int) kHlpHeapInit(void)
+{
+    return khlpHeapInit(&g_Heap);
+}
+
+
+/**
+ * Terminates the kLdr heap.
+ */
+KHLP_DECL(void) kHlpHeapTerm(void)
+{
+    khlpHeapDelete(&g_Heap);
+}
+
+
+KHLP_DECL(void *) kHlpAlloc(KSIZE cb)
+{
+    return khlpHeapAlloc(&g_Heap, cb);
+}
+
+
+KHLP_DECL(void *) kHlpAllocZ(KSIZE cb)
+{
+    void *pv = khlpHeapAlloc(&g_Heap, cb);
+    if (pv)
+        kHlpMemSet(pv, 0, cb);
+    return pv;
+}
+
+
+KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb)
+{
+    void *pvNew = khlpHeapAlloc(&g_Heap, cb);
+    if (pvNew)
+        kHlpMemCopy(pvNew, pv, cb);
+    return pvNew;
+}
+
+
+KHLP_DECL(char *) kHlpStrDup(const char *psz)
+{
+    return (char *)kHlpDup(psz, kHlpStrLen(psz) + 1);
+}
+
+
+KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb)
+{
+    void *pvNew;
+    if (!cb)
+    {
+        kHlpFree(pv);
+        pvNew = NULL;
+    }
+    else if (!pv)
+        pvNew = khlpHeapAlloc(&g_Heap, cb);
+    else
+    {
+        KSIZE cbToCopy = khlpHeapBlockSize(&g_Heap, pv);
+        pvNew = khlpHeapAlloc(&g_Heap, cb);
+        if (pvNew)
+        {
+            kHlpMemCopy(pvNew, pv, cb);
+            kHlpFree(pv);
+        }
+    }
+    return pvNew;
+}
+
+
+KHLP_DECL(void) kHlpFree(void *pv)
+{
+    khlpHeapFree(&g_Heap, pv);
+}
+
+
+/**
+ * Donates memory to the heap.
+ *
+ * @param   pv      The address of the memory.
+ * @param   cb      The amount of memory.
+ */
+KHLP_DECL(void) kHlpHeapDonate(void *pv, KSIZE cb)
+{
+    khlpHeapDonate(&g_Heap, pv, cb);
+}
+
+
+
+/**
+ * Initializes the heap anchor.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   pHeap   The heap anchor to be initialized.
+ */
+static int khlpHeapInit(PKHLPHEAPANCHOR pHeap)
+{
+    pHeap->pHead = NULL;
+    pHeap->pTail = NULL;
+    pHeap->pFreeHead = NULL;
+    pHeap->SegsHead.pNext = NULL;
+    pHeap->SegsHead.cSegs = 0;
+    return 0;
+}
+
+
+/**
+ * Deletes a heap.
+ * This will free all resources (memory) associated with the heap.
+ *
+ * @param   pHeap   The heap to be deleted.
+ */
+static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap)
+{
+    /*
+     * Free the segments, LIFO order.
+     * The head element is the last to be free, while the
+     * head.pNext is really the tail pointer - neat or what?
+     */
+    while (     pHeap->SegsHead.cSegs
+           ||   pHeap->SegsHead.pNext)
+    {
+        /* find the tail. */
+        KU32            iSeg;
+        PKHLPHEAPSEGS   pSegs = pHeap->SegsHead.pNext;
+        if (!pSegs)
+            pSegs = &pHeap->SegsHead;
+        else
+        {
+            pHeap->SegsHead.pNext = pSegs->pNext;
+            pSegs->pNext = NULL;
+        }
+
+        /* free the segments */
+        iSeg = pSegs->cSegs;
+        while (iSeg-- > 0)
+            khlpHeapSegFree(&pSegs->aSegs[iSeg]);
+        pSegs->cSegs = 0;
+    }
+
+    /* Zap the anchor. */
+    pHeap->pHead = NULL;
+    pHeap->pTail = NULL;
+    pHeap->pFreeHead = NULL;
+    pHeap->SegsHead.pNext = NULL;
+    pHeap->SegsHead.cSegs = 0;
+}
+
+
+/**
+ * Internal heap block allocator.
+ */
+static void *   kldrHeapAllocSub(PKHLPHEAPANCHOR pHeap, KSIZE cb)
+{
+    /*
+     * Find a fitting free block.
+     */
+    const KSIZE     cbReq = K_ALIGN_Z(cb + sizeof(KHLPHEAPBLOCK), KHLPHEAPBLOCK_ALIGNMENT);
+    PKHLPHEAPFREE   pCur = pHeap->pFreeHead;
+    while (pCur)
+    {
+        if (pCur->Core.cb >= cbReq)
+        {
+            if (pCur->Core.cb != cbReq)
+            {
+                /* check and see if there is a better match close by. */
+                PKHLPHEAPFREE pCur2 = pCur->pNext;
+                unsigned i = 16;
+                while (i-- > 0 && pCur2)
+                {
+                    if (pCur2->Core.cb >= cbReq)
+                    {
+                        if (pCur2->Core.cb == cbReq)
+                        {
+                            pCur = pCur2;
+                            break;
+                        }
+                        if (pCur2->Core.cb < pCur->Core.cb)
+                            pCur = pCur2;
+                    }
+
+                    /* next */
+                    KHLPHEAP_ASSERT_FREE(pHeap, pCur2);
+                    pCur2 = pCur2->pNext;
+                }
+            }
+            break;
+        }
+
+        /* next */
+        KHLPHEAP_ASSERT_FREE(pHeap, pCur);
+        pCur = pCur->pNext;
+    }
+    if (!pCur)
+        return NULL;
+    KHLPHEAP_ASSERT_FREE(pHeap, pCur);
+
+    /*
+     * Do we need to split out a block?
+     */
+    if (pCur->Core.cb - cbReq >= KHLPHEAPBLOCK_ALIGNMENT * 2)
+    {
+        PKHLPHEAPBLOCK pNew;
+
+        pCur->Core.cb -= cbReq;
+
+        pNew = (PKHLPHEAPBLOCK)((KUPTR)pCur + pCur->Core.cb);
+        pNew->fFlags = 0;
+        pNew->cb = cbReq;
+        pNew->pNext = pCur->Core.pNext;
+        if (pNew->pNext)
+            pNew->pNext->pPrev = pNew;
+        else
+            pHeap->pTail = pNew;
+        pNew->pPrev = &pCur->Core;
+        pCur->Core.pNext = pNew;
+
+        KHLPHEAP_ASSERT_FREE(pHeap, pCur);
+        KHLPHEAP_ASSERT_BLOCK(pHeap, pNew);
+        return pNew + 1;
+    }
+
+    /*
+     * No, just unlink it from the free list and return.
+     */
+    if (pCur->pNext)
+        pCur->pNext->pPrev = pCur->pPrev;
+    if (pCur->pPrev)
+        pCur->pPrev->pNext = pCur->pNext;
+    else
+        pHeap->pFreeHead = pCur->pNext;
+    pCur->Core.fFlags &= ~KHLPHEAPBLOCK_FLAG_FREE;
+
+    KHLPHEAP_ASSERT_BLOCK(pHeap, &pCur->Core);
+    return &pCur->Core + 1;
+}
+
+
+/**
+ * Allocate a heap block.
+ *
+ * @returns Pointer to the allocated heap block on success. On failure NULL is returned.
+ * @param   pHeap   The heap.
+ * @param   cb      The requested heap block size.
+ */
+static void *   khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb)
+{
+    void *pv;
+
+    /* adjust the requested block size. */
+    cb = K_ALIGN_Z(cb, KHLPHEAPBLOCK_ALIGNMENT);
+    if (!cb)
+        cb = KHLPHEAPBLOCK_ALIGNMENT;
+
+    /* try allocate the block. */
+    pv = kldrHeapAllocSub(pHeap, cb);
+    if (!pv)
+    {
+        /*
+         * Failed, add another segment and try again.
+         */
+        KHLPHEAPSEG Seg;
+        if (khlpHeapSegAlloc(&Seg, cb + sizeof(KHLPHEAPSEGS) + sizeof(KHLPHEAPBLOCK) * 16))
+            return NULL;
+
+        /* donate before insterting the segment, this makes sure we got heap to expand the segment list. */
+        khlpHeapDonate(pHeap, Seg.pvBase, Seg.cb);
+
+        /* insert the segment. */
+        if (pHeap->SegsHead.cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0]))
+            pHeap->SegsHead.aSegs[pHeap->SegsHead.cSegs++] = Seg;
+        else if (   pHeap->SegsHead.pNext
+                 && pHeap->SegsHead.pNext->cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0]))
+            pHeap->SegsHead.pNext->aSegs[pHeap->SegsHead.pNext->cSegs++] = Seg;
+        else
+        {
+            PKHLPHEAPSEGS pSegs = (PKHLPHEAPSEGS)kldrHeapAllocSub(pHeap, sizeof(*pSegs));
+            KHLPHEAP_ASSERT(pSegs);
+            pSegs->pNext = pHeap->SegsHead.pNext;
+            pHeap->SegsHead.pNext = pSegs;
+            pSegs->aSegs[0] = Seg;
+            pSegs->cSegs = 1;
+        }
+
+        /* retry (should succeed) */
+        pv = kldrHeapAllocSub(pHeap, cb);
+        KHLPHEAP_ASSERT(pv);
+    }
+
+    return pv;
+}
+
+
+/**
+ * Frees a heap block.
+ *
+ * @param   pHeap   The heap.
+ * @param   pv      The pointer returned by khlpHeapAlloc().
+ */
+static void     khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv)
+{
+    PKHLPHEAPFREE pFree, pLeft, pRight;
+
+    /* ignore NULL pointers. */
+    if (!pv)
+        return;
+
+    pFree = (PKHLPHEAPFREE)((PKHLPHEAPBLOCK)pv - 1);
+    KHLPHEAP_ASSERT_BLOCK(pHeap, &pFree->Core);
+    KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(&pFree->Core));
+
+    /*
+     * Merge or link with left node?
+     */
+    pLeft = (PKHLPHEAPFREE)pFree->Core.pPrev;
+    if (    pLeft
+        &&  KHLPHEAPBLOCK_IS_FREE(&pLeft->Core)
+        &&  KHLPHEAPBLOCK_IS_ADJACENT(&pLeft->Core, &pFree->Core)
+       )
+    {
+        /* merge left */
+        pLeft->Core.pNext = pFree->Core.pNext;
+        if (pFree->Core.pNext)
+            pFree->Core.pNext->pPrev = &pLeft->Core;
+        else
+            pHeap->pTail = &pLeft->Core;
+
+        pLeft->Core.cb += pFree->Core.cb;
+        pFree->Core.fFlags = ~0;
+        pFree = pLeft;
+    }
+    else
+    {
+        /* link left */
+        while (pLeft && !KHLPHEAPBLOCK_IS_FREE(&pLeft->Core))
+            pLeft = (PKHLPHEAPFREE)pLeft->Core.pPrev;
+        if (pLeft)
+        {
+            pFree->pPrev = pLeft;
+            pFree->pNext = pLeft->pNext;
+            if (pLeft->pNext)
+                pLeft->pNext->pPrev = pFree;
+            pLeft->pNext  = pFree;
+        }
+        else
+        {
+            pFree->pPrev = NULL;
+            pFree->pNext = pHeap->pFreeHead;
+            if (pHeap->pFreeHead)
+                pHeap->pFreeHead->pPrev = pFree;
+            pHeap->pFreeHead = pFree;
+        }
+        pFree->Core.fFlags |= KHLPHEAPBLOCK_FLAG_FREE;
+    }
+    KHLPHEAP_ASSERT_FREE(pHeap, pFree);
+
+    /*
+     * Merge right?
+     */
+    pRight = (PKHLPHEAPFREE)pFree->Core.pNext;
+    if (    pRight
+        &&  KHLPHEAPBLOCK_IS_FREE(&pRight->Core)
+        &&  KHLPHEAPBLOCK_IS_ADJACENT(&pFree->Core, pRight)
+       )
+    {
+        /* unlink pRight from the global list. */
+        pFree->Core.pNext = pRight->Core.pNext;
+        if (pRight->Core.pNext)
+            pRight->Core.pNext->pPrev = &pFree->Core;
+        else
+            pHeap->pTail = &pFree->Core;
+
+        /* unlink pRight from the free list. */
+        pFree->pNext = pRight->pNext;
+        if (pRight->pNext)
+            pRight->pNext->pPrev = pFree;
+
+        /* update size and invalidate pRight. */
+        pFree->Core.cb += pRight->Core.cb;
+        pRight->Core.fFlags = ~0;
+    }
+}
+
+
+/**
+ * Calcs the size of a heap block.
+ *
+ * @returns The block size (in bytes).
+ * @param   pHeap       The heap.
+ * @param   pv          Pointer to an in-use heap block.
+ */
+static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv)
+{
+    PKHLPHEAPBLOCK pBlock  = (PKHLPHEAPBLOCK)pv - 1;
+    KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock);
+    KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(pBlock));
+    return (KU8 *)pBlock->pNext - (KU8 *)pv;
+}
+
+
+/**
+ * Donates memory to the heap.
+ *
+ * The donated memory is returned to the donator when the heap is deleted.
+ *
+ * @param pHeap The heap
+ * @param pv    The pointer to the donated memory.
+ * @param cb    Size of the donated memory.
+ */
+static void     khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb)
+{
+    PKHLPHEAPBLOCK pBlock;
+
+    /*
+     * Don't bother with small donations.
+     */
+    if (cb < KHLPHEAPBLOCK_ALIGNMENT * 4)
+        return;
+
+    /*
+     * Align the donation on a heap block boundrary.
+     */
+    if ((KUPTR)pv & (KHLPHEAPBLOCK_ALIGNMENT - 1))
+    {
+        cb -= (KUPTR)pv & 31;
+        pv = K_ALIGN_P(pv, KHLPHEAPBLOCK_ALIGNMENT);
+    }
+    cb &= ~(KSIZE)(KHLPHEAPBLOCK_ALIGNMENT - 1);
+
+    /*
+     * Create an allocated block, link it and free it.
+     */
+    pBlock = (PKHLPHEAPBLOCK)pv;
+    pBlock->pNext = NULL;
+    pBlock->pPrev = NULL;
+    pBlock->cb = cb;
+    pBlock->fFlags = 0;
+
+    /* insert */
+    if ((KUPTR)pBlock < (KUPTR)pHeap->pHead)
+    {
+        /* head */
+        pBlock->pNext = pHeap->pHead;
+        pHeap->pHead->pPrev = pBlock;
+        pHeap->pHead = pBlock;
+    }
+    else if ((KUPTR)pBlock > (KUPTR)pHeap->pTail)
+    {
+        if (pHeap->pTail)
+        {
+            /* tail */
+            pBlock->pPrev = pHeap->pTail;
+            pHeap->pTail->pNext = pBlock;
+            pHeap->pTail = pBlock;
+        }
+        else
+        {
+            /* first */
+            pHeap->pHead = pBlock;
+            pHeap->pTail = pBlock;
+        }
+    }
+    else
+    {
+        /* in list (unlikely) */
+        PKHLPHEAPBLOCK pPrev = pHeap->pHead;
+        PKHLPHEAPBLOCK pCur = pPrev->pNext;
+        for (;;)
+        {
+            KHLPHEAP_ASSERT_BLOCK(pHeap, pCur);
+            if ((KUPTR)pCur > (KUPTR)pBlock)
+                break;
+            pPrev = pCur;
+            pCur = pCur->pNext;
+        }
+
+        pBlock->pNext = pCur;
+        pBlock->pPrev = pPrev;
+        pPrev->pNext = pBlock;
+        pCur->pPrev = pBlock;
+    }
+    KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock);
+
+    /* free it */
+    khlpHeapFree(pHeap, pBlock + 1);
+}
+
+
+
+/**
+ * Allocates a new segment.
+ *
+ * @returns 0 on success, non-zero OS status code on failure.
+ * @param   pSeg    Where to put the info about the allocated segment.
+ * @param   cbMin   The minimum segment size.
+ */
+static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cbMin)
+{
+#if K_OS == K_OS_OS2
+    APIRET rc;
+
+    pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff;
+    pSeg->pvBase = NULL;
+    rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY);
+    if (rc == ERROR_INVALID_PARAMETER)
+        rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE);
+    if (rc)
+    {
+        pSeg->pvBase = NULL;
+        pSeg->cb = 0;
+        return rc;
+    }
+
+#elif  K_OS == K_OS_WINDOWS
+    pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff;
+    pSeg->pvBase = VirtualAlloc(NULL, pSeg->cb, MEM_COMMIT, PAGE_READWRITE);
+    if (!pSeg->pvBase)
+    {
+        pSeg->cb = 0;
+        return GetLastError();
+    }
+
+#else
+    int rc;
+
+    pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff;
+    pSeg->pvBase = NULL;
+    rc = kHlpPageAlloc(&pSeg->pvBase, pSeg->cb, KPROT_READWRITE, K_FALSE);
+    if (rc)
+    {
+        pSeg->pvBase = NULL;
+        pSeg->cb = 0;
+        return rc;
+    }
+
+#endif
+
+    return 0;
+}
+
+
+/**
+ * Frees a segment.
+ *
+ * @param   pSeg    The segment to be freed.
+ */
+static void khlpHeapSegFree(PKHLPHEAPSEG pSeg)
+{
+#if K_OS == K_OS_OS2
+    APIRET rc = DosFreeMem(pSeg->pvBase);
+    KHLPHEAP_ASSERT(!rc); (void)rc;
+
+#elif  K_OS == K_OS_WINDOWS
+    BOOL fRc = VirtualFree(pSeg->pvBase, 0 /*pSeg->cb*/, MEM_RELEASE);
+    KHLPHEAP_ASSERT(fRc); (void)fRc;
+
+#else
+    int rc = kHlpPageFree(pSeg->pvBase, pSeg->cb);
+    KHLPHEAP_ASSERT(!rc); (void)rc;
+
+#endif
+}
+
Index: /trunk/kHlp/Bare/kHlpBareProcess.c
===================================================================
--- /trunk/kHlp/Bare/kHlpBareProcess.c	(revision 2)
+++ /trunk/kHlp/Bare/kHlpBareProcess.c	(revision 2)
@@ -0,0 +1,87 @@
+/* $Id$ */
+/** @file
+ * kHlpBare - Process Management
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpProcess.h>
+#include <k/kHlpAssert.h>
+
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+# include <k/kHlpSys.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+#elif  K_OS == K_OS_WINDOWS
+# include <Windows.h>
+#else
+# error "port me"
+#endif
+
+
+/**
+ * Terminate the process.
+ *
+ * @param   rc      The exit status.
+ */
+void    kHlpExit(int rc)
+{
+    for (;;)
+    {
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+        kHlpSys_exit(rc);
+
+#elif K_OS == K_OS_OS2
+        DosExit(EXIT_PROCESS, rc);
+
+#elif  K_OS == K_OS_WINDOWS
+        TerminateProcess(GetCurrentProcess(), rc);
+
+#else
+# error "Port me"
+#endif
+        kHlpAssert(!"Impossible");
+    }
+}
+
Index: /trunk/kHlp/Bare/kHlpBareThread.c
===================================================================
--- /trunk/kHlp/Bare/kHlpBareThread.c	(revision 2)
+++ /trunk/kHlp/Bare/kHlpBareThread.c	(revision 2)
@@ -0,0 +1,75 @@
+/* $Id$ */
+/** @file
+ * kHlpBare - Thread Manipulation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpThread.h>
+
+#if K_OS == K_OS_DARWIN
+
+#elif K_OS == K_OS_LINUX
+# include <k/kHlpSys.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+#elif  K_OS == K_OS_WINDOWS
+# include <Windows.h>
+#else
+# error "port me"
+#endif
+
+
+/**
+ * Sleep for a number of milliseconds.
+ * @param   cMillies    Number of milliseconds to sleep.
+ */
+void kHlpSleep(unsigned cMillies)
+{
+#if K_OS == K_OS_DARWIN
+    /** @todo mach_wait_until, see gen/nanosleep.c. */
+    usleep(cMillies * 1000);
+
+#elif K_OS == K_OS_LINUX
+    /** @todo find the right syscall... */
+
+#elif K_OS == K_OS_OS2
+    DosSleep(cMillies);
+#elif  K_OS == K_OS_WINDOWS
+    Sleep(cMillies);
+#else
+    usleep(cMillies * 1000);
+#endif
+}
+
Index: /trunk/kHlp/CRT/kHlpCRTAlloc.cpp
===================================================================
--- /trunk/kHlp/CRT/kHlpCRTAlloc.cpp	(revision 2)
+++ /trunk/kHlp/CRT/kHlpCRTAlloc.cpp	(revision 2)
@@ -0,0 +1,80 @@
+/* $Id$ */
+/** @file
+ * kHlpAlloc - Memory Allocation, CRT based implementation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpAlloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+KHLP_DECL(void *) kHlpAlloc(KSIZE cb)
+{
+    return malloc(cb);
+}
+
+
+KHLP_DECL(void *) kHlpAllocZ(KSIZE cb)
+{
+    return calloc(1, cb);
+}
+
+
+KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb)
+{
+    void *pvDup = kHlpAlloc(cb);
+    if (pvDup)
+        return memcpy(pvDup, pv, cb);
+    return NULL;
+}
+
+
+KHLP_DECL(char *) kHlpStrDup(const char *psz)
+{
+    size_t cb = strlen(psz) + 1;
+    return (char *)kHlpDup(psz, cb);
+}
+
+
+KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb)
+{
+    return realloc(pv, cb);
+}
+
+
+KHLP_DECL(void) kHlpFree(void *pv)
+{
+    if (pv)
+        free(pv);
+}
+
Index: /trunk/kHlp/CRT/kHlpCRTEnv.cpp
===================================================================
--- /trunk/kHlp/CRT/kHlpCRTEnv.cpp	(revision 2)
+++ /trunk/kHlp/CRT/kHlpCRTEnv.cpp	(revision 2)
@@ -0,0 +1,58 @@
+/* $Id$ */
+/** @file
+ * kHlpEnv - Environment Manipulation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpEnv.h>
+#include <k/kHlpString.h>
+#include <k/kErrors.h>
+#include <stdlib.h>
+
+
+KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal)
+{
+    int rc = 0;
+    const char *pszValue = getenv(pszVar);
+    if (pszValue)
+    {
+        KSIZE  cch = kHlpStrLen((const char *)pszValue);
+        if (cchVal > cch)
+            kHlpMemCopy(pszVal, pszValue, cch + 1);
+        else
+            rc = KERR_BUFFER_OVERFLOW;
+    }
+    else
+        rc = KERR_ENVVAR_NOT_FOUND;
+    return rc;
+}
+
Index: /trunk/kHlp/CRT/kHlpCRTString.cpp
===================================================================
--- /trunk/kHlp/CRT/kHlpCRTString.cpp	(revision 2)
+++ /trunk/kHlp/CRT/kHlpCRTString.cpp	(revision 2)
@@ -0,0 +1,166 @@
+/* $Id$ */
+/** @file
+ * kHlpString - String And Memory Routines, CRT based implementation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+#include <string.h>
+
+
+#ifndef kHlpMemChr
+void   *kHlpMemChr(const void *pv, int ch, KSIZE cb)
+{
+    return (void *)memchr(pv, ch, cb);
+}
+#endif
+
+
+#ifndef kHlpMemComp
+int     kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb)
+{
+    return memcmp(pv1, pv2, cb);
+}
+#endif
+
+
+#ifndef kHlpMemCopy
+void   *kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb)
+{
+    return memcpy(pv1, pv2, cb);
+}
+#endif
+
+
+#ifndef kHlpMemPCopy
+void   *kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb)
+{
+    return (KU8 *)memcpy(pv1, pv2, cb) + cb;
+}
+#endif
+
+
+#ifndef kHlpMemMove
+void   *kHlpMemMove(void *pv1, const void *pv2, KSIZE cb)
+{
+    return memmove(pv1, pv2, cb);
+}
+#endif
+
+
+#ifndef kHlpMemPMove
+void   *kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb)
+{
+    return (KU8 *)memmove(pv1, pv2, cb) + cb;
+}
+#endif
+
+
+#ifndef kHlpMemSet
+void   *kHlpMemSet(void *pv1, int ch, KSIZE cb)
+{
+    return memset(pv1, ch, cb);
+}
+#endif
+
+
+#ifndef kHlpMemPSet
+void   *kHlpMemPSet(void *pv1, int ch, KSIZE cb)
+{
+    return (KU8 *)memset(pv1, ch, cb) + cb;
+}
+#endif
+
+
+#ifndef kHlpStrCat
+char   *kHlpStrCat(char *psz1, const char *psz2)
+{
+    return strcat(psz1, psz2);
+}
+#endif
+
+
+#ifndef kHlpStrNCat
+char   *kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb)
+{
+    return strncat(psz1, psz2, cb);
+}
+#endif
+
+
+#ifndef kHlpStrChr
+char   *kHlpStrChr(const char *psz, int ch)
+{
+    return (char *)strchr(psz, ch);
+}
+#endif
+
+
+#ifndef kHlpStrRChr
+char   *kHlpStrRChr(const char *psz, int ch)
+{
+    return (char *)strrchr(psz, ch);
+}
+#endif
+
+
+#ifndef kHlpStrComp
+int     kHlpStrComp(const char *psz1, const char *psz2)
+{
+    return strcmp(psz1, psz2);
+}
+#endif
+
+
+#ifndef kHlpStrNComp
+int     kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cch)
+{
+    return strncmp(psz1, psz2, cch);
+}
+#endif
+
+
+#ifndef kHlpStrCopy
+char   *kHlpStrCopy(char *psz1, const char *psz2)
+{
+    return strcpy(psz1, psz2);
+}
+#endif
+
+
+#ifndef kHlpStrLen
+KSIZE   kHlpStrLen(const char *psz1)
+{
+    return strlen(psz1);
+}
+#endif
+
Index: /trunk/kHlp/Generic/kHlpGetEnvUZ.c
===================================================================
--- /trunk/kHlp/Generic/kHlpGetEnvUZ.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpGetEnvUZ.c	(revision 2)
@@ -0,0 +1,110 @@
+/* $Id$ */
+/** @file
+ * kHlpEnv - kHlpGetEnvUZ.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpEnv.h>
+#include <k/kHlpString.h>
+
+
+/**
+ * Gets an environment variable and converts it to a KSIZE.
+ *
+ * @returns 0 and *pcb on success.
+ * @returns On failure see kHlpGetEnv.
+ * @param   pszVar  The name of the variable.
+ * @param   pcb     Where to put the value.
+ */
+KHLP_DECL(int) kHlpGetEnvUZ(const char *pszVar, KSIZE *pcb)
+{
+    KSIZE       cb;
+    unsigned    uBase;
+    char        szVal[64];
+    KSIZE       cchVal = sizeof(szVal);
+    const char *psz;
+    int         rc;
+
+    *pcb = 0;
+    rc = kHlpGetEnv(pszVar, szVal, cchVal);
+    if (rc)
+        return rc;
+
+    /* figure out the base. */
+    uBase = 10;
+    psz = szVal;
+    if (    *psz == '0'
+        &&  (psz[1] == 'x' || psz[1] == 'X'))
+    {
+        uBase = 16;
+        psz += 2;
+    }
+
+    /* convert it up to the first unknown char. */
+    cb = 0;
+    for(;;)
+    {
+        const char ch = *psz;
+        unsigned uDigit;
+        if (!ch)
+            break;
+        else if (ch >= '0' && ch <= '9')
+            uDigit = ch - '0';
+        else if (ch >= 'a' && ch <= 'z')
+            uDigit = ch - 'a' + 10;
+        else if (ch >= 'A' && ch <= 'Z')
+            uDigit = ch - 'A' + 10;
+        else
+            break;
+        if (uDigit >= uBase)
+            break;
+
+        /* add the digit */
+        cb *= uBase;
+        cb += uDigit;
+
+        psz++;
+    }
+
+    /* check for unit */
+    if (*psz == 'm' || *psz == 'M')
+        cb *= 1024*1024;
+    else if (*psz == 'k' ||*psz == 'K')
+        cb *= 1024;
+    else if (*psz == 'g' || *psz == 'G')
+        cb *= 1024*1024*1024;
+
+    *pcb = cb;
+    return 0;
+}
+
+
Index: /trunk/kHlp/Generic/kHlpGetExt.c
===================================================================
--- /trunk/kHlp/Generic/kHlpGetExt.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpGetExt.c	(revision 2)
@@ -0,0 +1,80 @@
+/* $Id$ */
+/** @file
+ * kHlpPath - kHlpGetExt and kHlpGetSuff.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpPath.h>
+#include <k/kHlpString.h>
+
+
+/**
+ * Gets the filename suffix.
+ *
+ * @returns Pointer to where the suffix starts within the string pointed to by pszFilename.
+ * @returns Pointer to the terminator char if no suffix.
+ * @param   pszFilename     The filename to parse.
+ */
+KHLP_DECL(char *) kHlpGetSuff(const char *pszFilename)
+{
+    const char *pszDot = NULL;
+    pszFilename = kHlpGetFilename(pszFilename);
+    for (;;)
+    {
+        char ch = *pszFilename;
+        if (ch == '.')
+        {
+            while ((ch = *++pszFilename) == '.')
+                /* nothing */;
+            if (ch)
+                pszDot = pszFilename - 1;
+        }
+        if (!ch)
+            return (char *)(pszDot ? pszDot : pszFilename);
+        pszFilename++;
+    }
+}
+
+
+/**
+ * Gets the filename extention.
+ *
+ * @returns Pointer to where the extension starts within the string pointed to by pszFilename.
+ * @returns Pointer to the terminator char if no extension.
+ * @param   pszFilename     The filename to parse.
+ */
+KHLP_DECL(char *) kHlpGetExt(const char *pszFilename)
+{
+    char *psz = kHlpGetSuff(pszFilename);
+    return *psz ? psz + 1 : psz;
+}
+
Index: /trunk/kHlp/Generic/kHlpGetFilename.c
===================================================================
--- /trunk/kHlp/Generic/kHlpGetFilename.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpGetFilename.c	(revision 2)
@@ -0,0 +1,73 @@
+/* $Id$ */
+/** @file
+ * kHlpPath - kHlpGetFilename.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpPath.h>
+#include <k/kHlpString.h>
+
+
+/**
+ * Get the pointer to the filename part of the name.
+ *
+ * @returns Pointer to where the filename starts within the string pointed to by pszFilename.
+ * @returns Pointer to the terminator char if no filename.
+ * @param   pszFilename     The filename to parse.
+ */
+KHLP_DECL(char *) kHlpGetFilename(const char *pszFilename)
+{
+    const char *pszLast = NULL;
+    for (;;)
+    {
+        char ch = *pszFilename;
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+        if (ch == '/' || ch == '\\' || ch == ':')
+        {
+            while ((ch = *++pszFilename) == '/' || ch == '\\' || ch == ':')
+                /* nothing */;
+            pszLast = pszFilename;
+        }
+#else
+        if (ch == '/')
+        {
+            while ((ch = *++pszFilename) == '/')
+                /* betsuni */;
+            pszLast = pszFilename;
+        }
+#endif
+        if (!ch)
+            return (char *)(pszLast ? pszLast : pszFilename);
+        pszFilename++;
+    }
+}
+
Index: /trunk/kHlp/Generic/kHlpInt2Ascii.c
===================================================================
--- /trunk/kHlp/Generic/kHlpInt2Ascii.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpInt2Ascii.c	(revision 2)
@@ -0,0 +1,85 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpInt2Ascii.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+/**
+ * Converts an signed integer to an ascii string.
+ *
+ * @returns psz.
+ * @param   psz         Pointer to the output buffer.
+ * @param   cch         The size of the output buffer.
+ * @param   lVal        The value.
+ * @param   iBase       The base to format it. (2,8,10 or 16)
+ */
+KHLP_DECL(char *) kHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase)
+{
+    static const char s_szDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+    char *pszRet = psz;
+
+    if (cch >= (lVal < 0 ? 3U : 2U) && psz)
+    {
+        /* prefix */
+        if (lVal < 0)
+        {
+            *psz++ = '-';
+            cch--;
+            lVal = -lVal;
+        }
+
+        /* the digits */
+        do
+        {
+            *psz++ = s_szDigits[lVal % iBase];
+            cch--;
+            lVal /= iBase;
+        } while (lVal && cch > 1);
+
+        /* overflow indicator */
+        if (lVal)
+            psz[-1] = '+';
+    }
+    else if (!pszRet)
+        return pszRet;
+    else if (cch < 1 || !pszRet)
+        return pszRet;
+    else
+        *psz++ = '+';
+    *psz = '\0';
+
+    return pszRet;
+}
+
Index: /trunk/kHlp/Generic/kHlpIsFilenameOnly.c
===================================================================
--- /trunk/kHlp/Generic/kHlpIsFilenameOnly.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpIsFilenameOnly.c	(revision 2)
@@ -0,0 +1,63 @@
+/* $Id$ */
+/** @file
+ * kHlpPath - kHlpIsFilenameOnly.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpPath.h>
+#include <k/kHlpString.h>
+
+
+/**
+ * Checks if this is only a filename or if it contains any kind
+ * of drive, directory, or server specs.
+ *
+ * @returns 1 if this is a filename only.
+ * @returns 0 of it's isn't only a filename.
+ * @param   pszFilename     The filename to parse.
+ */
+KHLP_DECL(int) kHlpIsFilenameOnly(const char *pszFilename)
+{
+    for (;;)
+    {
+        const char ch = *pszFilename++;
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+        if (ch == '/' || ch == '\\' || ch == ':')
+#else
+        if (ch == '/')
+#endif
+            return 0;
+        if (!ch)
+            return 1;
+    }
+}
+
Index: /trunk/kHlp/Generic/kHlpMemChr.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemChr.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemChr.c	(revision 2)
@@ -0,0 +1,53 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemChr.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(void *) kHlpMemChr(const void *pv1, int ch, KSIZE cb)
+{
+    const KU8 b = ch;
+    const KU8 *pb = (const KU8 *)pv1;
+
+    while (cb-- > 0)
+    {
+        if (*pb == b)
+            return (void *)pb;
+        pb++;
+    }
+
+    return NULL;
+}
+
Index: /trunk/kHlp/Generic/kHlpMemComp.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemComp.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemComp.c	(revision 2)
@@ -0,0 +1,73 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemComp.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(int) kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb)
+{
+    union
+    {
+        const void *pv;
+        const KU8 *pb;
+        const KUPTR *pu;
+    } u1, u2;
+
+    u1.pv = pv1;
+    u2.pv = pv2;
+
+    if (cb >= 32)
+    {
+        while (cb > sizeof(KUPTR))
+        {
+            cb -= sizeof(KUPTR);
+            if (*u1.pu != *u2.pu)
+                return *u1.pu > *u2.pu ? 1 : -1;
+            u1.pu++;
+            u2.pu++;
+        }
+    }
+
+    while (cb-- > 0)
+    {
+        if (u1.pb != u2.pb)
+            return u1.pb > u2.pb ? 1 : -1;
+        u1.pb++;
+        u2.pb++;
+    }
+
+    return 0;
+}
+
Index: /trunk/kHlp/Generic/kHlpMemCopy.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemCopy.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemCopy.c	(revision 2)
@@ -0,0 +1,71 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemCopy.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(void *) kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb)
+{
+    union
+    {
+        void *pv;
+        KU8 *pb;
+        KUPTR *pu;
+    } u1;
+    union
+    {
+        const void *pv;
+        const KU8 *pb;
+        const KUPTR *pu;
+    } u2;
+
+    u1.pv = pv1;
+    u2.pv = pv2;
+
+    if (cb >= 32)
+    {
+        while (cb > sizeof(KUPTR))
+        {
+            cb -= sizeof(KUPTR);
+            *u1.pu++ = *u2.pu++;
+        }
+    }
+
+    while (cb-- > 0)
+        *u1.pb++ = *u2.pb++;
+
+    return pv1;
+}
+
Index: /trunk/kHlp/Generic/kHlpMemICompAscii.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemICompAscii.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemICompAscii.c	(revision 2)
@@ -0,0 +1,82 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemICompAscii.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(int) kHlpMemICompAscii(const void *pv1, const void *pv2, KSIZE cb)
+{
+    union
+    {
+        const void *pv;
+        const KU8 *pb;
+        const KUPTR *pu;
+    } u1, u2;
+
+    u1.pv = pv1;
+    u2.pv = pv2;
+
+    if (cb >= 32)
+    {
+        while (cb > sizeof(KUPTR))
+        {
+            if (*u1.pu != *u2.pu)
+                break; /* hand it on to the byte-by-byte routine. */
+            u1.pu++;
+            u2.pu++;
+            cb -= sizeof(KUPTR);
+        }
+    }
+
+    while (cb-- > 0)
+    {
+        if (u1.pb != u2.pb)
+        {
+            KU8 ch1 = *u1.pb;
+            KU8 ch2 = *u2.pb;
+            if (ch1 <= 'Z' && ch1 >= 'A')
+                ch1 += 'a' - 'A';
+            if (ch2 <= 'Z' && ch2 >= 'A')
+                ch2 += 'a' - 'A';
+            if (ch1 != ch2)
+                return ch1 > ch2 ? 1 : -1;
+        }
+        u1.pb++;
+        u2.pb++;
+    }
+
+    return 0;
+}
+
Index: /trunk/kHlp/Generic/kHlpMemMove.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemMove.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemMove.c	(revision 2)
@@ -0,0 +1,102 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemMove.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(void *) kHlpMemMove(void *pv1, const void *pv2, KSIZE cb)
+{
+    union
+    {
+        void *pv;
+        KU8 *pb;
+        KUPTR *pu;
+    } u1;
+    union
+    {
+        const void *pv;
+        volatile KU8 *pb;
+        volatile KUPTR *pu;
+    } u2;
+
+    u1.pv = pv1;
+    u2.pv = pv2;
+
+    if ((KUPTR)u1.pb <= (KUPTR)u2.pb)
+    {
+        /* forward copy */
+        if (cb >= 32)
+        {
+            while (cb > sizeof(KUPTR))
+            {
+                KUPTR u = *u2.pu++;
+                *u1.pu++ = u;
+                cb -= sizeof(KUPTR);
+            }
+        }
+
+        while (cb-- > 0)
+        {
+            KU8 b = *u2.pb++;
+            *u1.pb++ = b;
+        }
+    }
+    else
+    {
+        /* backwards copy */
+        u1.pb += cb;
+        u2.pb += cb;
+
+        if (cb >= 32)
+        {
+            while (cb > sizeof(KUPTR))
+            {
+                KUPTR u = *--u2.pu;
+                *--u1.pu = u;
+                cb -= sizeof(KUPTR);
+            }
+        }
+
+        while (cb-- > 0)
+        {
+            KU8 b = *--u2.pb;
+            *--u1.pb = b;
+        }
+    }
+
+    return pv1;
+}
+
+
Index: /trunk/kHlp/Generic/kHlpMemPComp.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemPComp.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemPComp.c	(revision 2)
@@ -0,0 +1,73 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemPComp.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(void *) kHlpMemPComp(const void *pv1, const void *pv2, KSIZE cb)
+{
+    union
+    {
+        const void *pv;
+        const KU8 *pb;
+        const KUPTR *pu;
+    } u1, u2;
+
+    u1.pv = pv1;
+    u2.pv = pv2;
+
+    if (cb >= 32)
+    {
+        while (cb > sizeof(KUPTR))
+        {
+            if (*u1.pu != *u2.pu)
+                break; /* over to mr. byte-by-byte */
+            u1.pu++;
+            u2.pu++;
+            cb -= sizeof(KUPTR);
+        }
+    }
+
+    while (cb-- > 0)
+    {
+        if (u1.pb != u2.pb)
+            return (void *)u1.pb;
+        u1.pb++;
+        u2.pb++;
+    }
+
+    return NULL;
+}
+
Index: /trunk/kHlp/Generic/kHlpMemPCopy.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemPCopy.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemPCopy.c	(revision 2)
@@ -0,0 +1,71 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemPCopy.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(void *) kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb)
+{
+    union
+    {
+        void *pv;
+        KU8 *pb;
+        KUPTR *pu;
+    } u1;
+    union
+    {
+        const void *pv;
+        const KU8 *pb;
+        const KUPTR *pu;
+    } u2;
+
+    u1.pv = pv1;
+    u2.pv = pv2;
+
+    if (cb >= 32)
+    {
+        while (cb > sizeof(KUPTR))
+        {
+            cb -= sizeof(KUPTR);
+            *u1.pu++ = *u2.pu++;
+        }
+    }
+
+    while (cb-- > 0)
+        *u1.pb++ = *u2.pb++;
+
+    return u1.pb;
+}
+
Index: /trunk/kHlp/Generic/kHlpMemPMove.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemPMove.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemPMove.c	(revision 2)
@@ -0,0 +1,101 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemPMove.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(void *) kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb)
+{
+    union
+    {
+        void *pv;
+        KU8 *pb;
+        KUPTR *pu;
+    } u1;
+    union
+    {
+        const void *pv;
+        volatile KU8 *pb;
+        volatile KUPTR *pu;
+    } u2;
+
+    u1.pv = pv1;
+    u2.pv = pv2;
+
+    if ((KUPTR)u1.pb <= (KUPTR)u2.pb)
+    {
+        /* forwards copy */
+        if (cb >= 32)
+        {
+            while (cb > sizeof(KUPTR))
+            {
+                KUPTR u = *u2.pu++;
+                *u1.pu++ = u;
+                cb -= sizeof(KUPTR);
+            }
+        }
+
+        while (cb-- > 0)
+        {
+            KU8 b = *u2.pb++;
+            *u1.pb++ = b;
+        }
+
+        return u1.pb;
+    }
+
+    /* backwards copy */
+    u1.pb += cb;
+    u2.pb += cb;
+
+    if (cb >= 32)
+    {
+        while (cb > sizeof(KUPTR))
+        {
+            KUPTR u = *--u2.pu;
+            *--u1.pu = u;
+            cb -= sizeof(KUPTR);
+        }
+    }
+
+    while (cb-- > 0)
+    {
+        KU8 b = *--u2.pb;
+        *--u1.pb = b;
+    }
+
+    return (KU8 *)pv1 + cb;
+}
+
Index: /trunk/kHlp/Generic/kHlpMemPSet.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemPSet.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemPSet.c	(revision 2)
@@ -0,0 +1,79 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemPSet.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(void *) kHlpMemPSet(void *pv1, int ch, KSIZE cb)
+{
+    union
+    {
+        void *pv;
+        KU8 *pb;
+        KUPTR *pu;
+    } u1;
+
+    u1.pv = pv1;
+
+    if (cb >= 32)
+    {
+        KUPTR u = ch & 0xff;
+#if K_ARCH_BITS > 8
+        u |= u << 8;
+#endif
+#if K_ARCH_BITS > 16
+        u |= u << 16;
+#endif
+#if K_ARCH_BITS > 32
+        u |= u << 32;
+#endif
+#if K_ARCH_BITS > 64
+        u |= u << 64;
+#endif
+
+        while (cb > sizeof(KUPTR))
+        {
+            cb -= sizeof(KUPTR);
+            *u1.pu++ = u;
+        }
+    }
+
+    while (cb-- > 0)
+        *u1.pb++ = ch;
+
+    return u1.pb;
+}
+
+
Index: /trunk/kHlp/Generic/kHlpMemSet.c
===================================================================
--- /trunk/kHlp/Generic/kHlpMemSet.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpMemSet.c	(revision 2)
@@ -0,0 +1,78 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpMemSet.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(void *) kHlpMemSet(void *pv1, int ch, KSIZE cb)
+{
+    union
+    {
+        void *pv;
+        KU8 *pb;
+        KUPTR *pu;
+    } u1;
+
+    u1.pv = pv1;
+
+    if (cb >= 32)
+    {
+        KUPTR u = ch & 0xff;
+#if K_ARCH_BITS > 8
+        u |= u << 8;
+#endif
+#if K_ARCH_BITS > 16
+        u |= u << 16;
+#endif
+#if K_ARCH_BITS > 32
+        u |= u << 32;
+#endif
+#if K_ARCH_BITS > 64
+        u |= u << 64;
+#endif
+
+        while (cb > sizeof(KUPTR))
+        {
+            cb -= sizeof(KUPTR);
+            *u1.pu++ = u;
+        }
+    }
+
+    while (cb-- > 0)
+        *u1.pb++ = ch;
+
+    return pv1;
+}
+
Index: /trunk/kHlp/Generic/kHlpPage.c
===================================================================
--- /trunk/kHlp/Generic/kHlpPage.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpPage.c	(revision 2)
@@ -0,0 +1,373 @@
+/* $Id$ */
+/** @file
+ * kHlp - Generic Page Memory Functions.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpAlloc.h>
+#include <k/kHlpAssert.h>
+
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+# include <k/kHlpSys.h>
+# include <sys/mman.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif  K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#else
+# error "port me"
+#endif
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+/* nothing */
+#elif K_OS == K_OS_OS2
+/** The base of the loader stub object. <kLdr Hack>
+ * The OS/2 exe stub consists of a single data object. When allocating memory
+ * for an executable, we'll have to reuse this. */
+static void            *g_pvStub = NULL;
+/** The size of the stub object - 0 if no stub. <kLdr Hack> */
+static KSIZE            g_cbStub = 0;
+
+#elif  K_OS == K_OS_WINDOWS
+/** The system info. */
+static SYSTEM_INFO      g_SystemInfo;
+#else
+# error "port me"
+#endif
+
+
+
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+static int kHlpPageProtToNative(KPROT enmProt)
+{
+    switch (enmProt)
+    {
+        case KPROT_NOACCESS:             return PROT_NONE;
+        case KPROT_READONLY:             return PROT_READ;
+        case KPROT_READWRITE:            return PROT_READ | PROT_WRITE;
+        case KPROT_EXECUTE:              return PROT_EXEC;
+        case KPROT_EXECUTE_READ:         return PROT_EXEC | PROT_READ;
+        case KPROT_EXECUTE_READWRITE:    return PROT_EXEC | PROT_READ | PROT_WRITE;
+        default:
+            kHlpAssert(0);
+            return ~0U;
+    }
+}
+
+#elif K_OS == K_OS_OS2
+static ULONG kHlpPageProtToNative(KPROT enmProt)
+{
+    switch (enmProt)
+    {
+        case KPROT_NOACCESS:             return PAG_EXECUTE | PAG_READ | PAG_WRITE;
+        case KPROT_READONLY:             return PAG_COMMIT | PAG_READ;
+        case KPROT_READWRITE:            return PAG_COMMIT | PAG_READ | PAG_WRITE;
+        case KPROT_EXECUTE:              return PAG_COMMIT | PAG_EXECUTE;
+        case KPROT_EXECUTE_READ:         return PAG_COMMIT | PAG_EXECUTE | PAG_READ;
+        case KPROT_EXECUTE_READWRITE:    return PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE;
+        default:
+            kHlpAssert(0);
+            return ~0U;
+    }
+}
+#elif  K_OS == K_OS_WINDOWS
+static DWORD kHlpPageProtToNative(KPROT enmProt)
+{
+    switch (enmProt)
+    {
+        case KPROT_NOACCESS:             return PAGE_NOACCESS;
+        case KPROT_READONLY:             return PAGE_READONLY;
+        case KPROT_READWRITE:            return PAGE_READWRITE;
+        case KPROT_EXECUTE:              return PAGE_EXECUTE;
+        case KPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
+        case KPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
+        default:
+            kHlpAssert(0);
+            return ~0U;
+    }
+}
+#endif
+
+
+
+/**
+ * Allocate a chunk of memory with page granularity.
+ *
+ * @returns 0 on success, non-zero OS status code on failure.
+ * @param   ppv         Where to store the address of the allocated memory.
+ *                      If fFixed is set, *ppv will on entry contain the desired address (page aligned).
+ * @param   cb          Number of bytes. Page aligned.
+ * @param   enmProt     The new protection. Copy-on-write is invalid.
+ */
+KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed)
+{
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    void *pv;
+
+    pv = kHlpSys_mmap(fFixed ? *ppv : NULL, cb, kHlpPageProtToNative(enmProt),
+                      fFixed ? MAP_FIXED | MAP_ANON: MAP_ANON, -1, 0);
+    if ((KIPTR)pv < 256)
+    {
+        kHlpAssert(0);
+        return (int)(KIPTR)pv; /** @todo convert errno to kErrors */
+    }
+    *ppv = pv;
+    return 0;
+
+#elif K_OS == K_OS_OS2
+    APIRET  rc;
+    ULONG   fFlags = kHlpPageProtToNative(enmProt);
+
+    if (!fFixed)
+    {
+        /* simple */
+        rc = DosAllocMem(ppv, cb, fFlags | OBJ_ANY);
+        if (rc == ERROR_INVALID_PARAMETER)
+            rc = DosAllocMem(ppv, cb, fFlags);
+    }
+    else
+    {
+        /* not so simple. */
+        /** @todo I've got code for this in libc somewhere. */
+        rc = -1;
+    }
+    if (!rc)
+        return 0;
+    kHlpAssert(0);
+    return rc;
+
+#elif  K_OS == K_OS_WINDOWS
+    /* (We don't have to care about the stub here, because the stub will be unmapped before we get here.) */
+    int     rc;
+    DWORD   fProt = kHlpPageProtToNative(enmProt);
+
+    if (!g_SystemInfo.dwPageSize)
+        GetSystemInfo(&g_SystemInfo);
+
+    *ppv = VirtualAlloc(fFixed ? *ppv : NULL, cb, MEM_COMMIT, fProt);
+    if (*ppv != NULL)
+        return 0;
+    rc = GetLastError();
+    kHlpAssert(0);
+    return rc;
+
+#else
+# error "port me"
+#endif
+}
+
+
+/**
+ * Change the protection of one or more pages in an allocation.
+ *
+ * (This will of course only work correctly on memory allocated by kHlpPageAlloc().)
+ *
+ * @returns 0 on success, non-zero OS status code on failure.
+ * @param   pv          First page. Page aligned.
+ * @param   cb          Number of bytes. Page aligned.
+ * @param   enmProt     The new protection. Copy-on-write is invalid.
+ */
+KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt)
+{
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    int rc;
+
+    rc = kHlpSys_mprotect(pv, cb, kHlpPageProtToNative(enmProt));
+    if (!rc)
+        return 0;
+    /** @todo convert errno -> kErrors */
+    kHlpAssert(0);
+    return rc;
+
+#elif K_OS == K_OS_OS2
+    APIRET      rc;
+    ULONG       fFlags = kHlpPageProtToNative(enmProt);
+
+    /*
+     * The non-stub pages.
+     */
+    rc = DosSetMem(pv, cb, fFlags);
+    if (rc && fFlags != PAG_DECOMMIT)
+        rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT);
+    if (rc)
+    {
+        /* Try page by page. */
+        while (cb > 0)
+        {
+            rc = DosSetMem(pv, 0x1000, fFlags);
+            if (rc && fFlags != PAG_DECOMMIT)
+                rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT);
+            if (rc)
+                return rc;
+            pv = (void *)((KUPTR)pv + 0x1000);
+            cb -= 0x1000;
+        }
+    }
+    kHlpAssert(!rc);
+    return rc;
+
+#elif  K_OS == K_OS_WINDOWS
+    DWORD fOldProt = 0;
+    DWORD fProt = kHlpPageProtToNative(enmProt);
+    int rc = 0;
+
+    if (!VirtualProtect(pv, cb, fProt, &fOldProt))
+    {
+        rc = GetLastError();
+        kHlpAssert(0);
+    }
+    return rc;
+#else
+# error "port me"
+#endif
+}
+
+
+/**
+ * Free memory allocated by kHlpPageAlloc().
+ *
+ * @returns 0 on success, non-zero OS status code on failure.
+ * @param   pv          The address returned by kHlpPageAlloc().
+ * @param   cb          The byte count requested from kHlpPageAlloc().
+ */
+KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb)
+{
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    int rc;
+
+    rc = kHlpSys_munmap(pv, cb);
+    if (!rc)
+        return 0;
+    /** @todo convert errno -> kErrors */
+    return rc;
+
+#elif K_OS == K_OS_OS2
+    APIRET rc;
+
+    /*
+     * Deal with any portion overlapping with the stub.
+     */
+    KUPTR offStub = (KUPTR)pv - (KUPTR)g_pvStub;
+    if (offStub < g_cbStub)
+    {
+        /* decommit the pages in the stub. */
+        KSIZE cbStub = K_MIN(g_cbStub - offStub, cb);
+        rc = DosSetMem(pv, cbStub, PAG_DECOMMIT);
+        if (rc)
+        {
+            /* Page by page, ignoring errors after the first success. */
+            while (cbStub > 0)
+            {
+                if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT))
+                    rc = 0;
+                pv = (void *)((KUPTR)pv + 0x1000);
+                cbStub -= 0x1000;
+                cb -= 0x1000;
+            }
+            if (rc)
+            {
+                kHlpAssert(!rc);
+                return rc;
+            }
+        }
+        else
+        {
+            cb -= cbStub;
+            if (!cb)
+                return 0;
+            pv = (void *)((KUPTR)pv + cbStub);
+        }
+    }
+
+    /*
+     * Free the object.
+     */
+    rc = DosFreeMem(pv);
+    kHlpAssert(!rc);
+    return rc;
+
+#elif  K_OS == K_OS_WINDOWS
+    /*
+     * Free the object.
+     */
+    int rc = 0;
+    if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE))
+    {
+        rc = GetLastError();
+        kHlpAssert(0);
+    }
+    return rc;
+
+#else
+# error "port me"
+#endif
+}
+
Index: /trunk/kHlp/Generic/kHlpStrCat.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrCat.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrCat.c	(revision 2)
@@ -0,0 +1,54 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrCat.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrCat(char *psz1, const char *psz2)
+{
+    char ch;
+    char *pszDst = psz1;
+
+    while (*pszDst != '\0')
+        pszDst++;
+    do
+    {
+        ch = *psz2++;
+        *pszDst++ = ch;
+    } while (ch != '\0');
+
+    return psz1;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrChr.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrChr.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrChr.c	(revision 2)
@@ -0,0 +1,58 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrChr.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrChr(const char *psz, int ch)
+{
+    if (!ch)
+    {
+        while (*psz)
+            psz++;
+        return (char *)psz;
+    }
+
+    for (;;)
+    {
+        int chCur = *psz;
+        if (chCur == ch)
+            return (char *)psz;
+        if (!chCur)
+            return NULL;
+        psz++;
+    }
+}
+
Index: /trunk/kHlp/Generic/kHlpStrComp.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrComp.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrComp.c	(revision 2)
@@ -0,0 +1,54 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrComp.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(int) kHlpStrComp(const char *psz1, const char *psz2)
+{
+    for (;;)
+    {
+        char ch1 = *psz1;
+        char ch2 = *psz2;
+        if (ch1 != ch2)
+            return ch1 > ch2 ? 1 : -1;
+        if (!ch1)
+            return 0;
+        psz1++;
+        psz2++;
+    }
+}
+
+
Index: /trunk/kHlp/Generic/kHlpStrCopy.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrCopy.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrCopy.c	(revision 2)
@@ -0,0 +1,48 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrCopy.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrCopy(char *pszDst, const char *pszSrc)
+{
+    char ch;
+    char *psz = pszDst;
+    do
+        *psz++ = ch = *pszSrc;
+    while (ch);
+    return pszDst;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrICompAscii.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrICompAscii.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrICompAscii.c	(revision 2)
@@ -0,0 +1,60 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrICompAscii.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(int) kHlpStrICompAscii(const char *psz1, const char *psz2)
+{
+    for (;;)
+    {
+        char ch1 = *psz1;
+        char ch2 = *psz2;
+        if (ch1 != ch2)
+        {
+            if (ch1 <= 'Z' && ch1 >= 'A')
+                ch1 += 'a' - 'A';
+            if (ch2 <= 'Z' && ch2 >= 'A')
+                ch2 += 'a' - 'A';
+            if (ch1 != ch2)
+                return ch1 > ch2 ? 1 : -1;
+        }
+        if (!ch1)
+            return 0;
+        psz1++;
+        psz2++;
+    }
+}
+
Index: /trunk/kHlp/Generic/kHlpStrIPCompAscii.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrIPCompAscii.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrIPCompAscii.c	(revision 2)
@@ -0,0 +1,61 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrIPCompAscii.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrIPCompAscii(const char *psz1, const char *psz2)
+{
+    for (;;)
+    {
+        char ch1 = *psz1;
+        char ch2 = *psz2;
+        if (ch1 != ch2)
+        {
+            if (ch1 <= 'Z' && ch1 >= 'A')
+                ch1 += 'a' - 'A';
+            if (ch2 <= 'Z' && ch2 >= 'A')
+                ch2 += 'a' - 'A';
+            if (ch1 != ch2)
+                return (char *)psz1;
+        }
+        if (!ch1)
+            return (char *)psz1;
+        psz1++;
+        psz2++;
+    }
+}
+
+
Index: /trunk/kHlp/Generic/kHlpStrLen.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrLen.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrLen.c	(revision 2)
@@ -0,0 +1,46 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrLen.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(KSIZE) kHlpStrLen(const char *psz)
+{
+    const char *pszEnd = psz;
+    while (*pszEnd)
+        pszEnd++;
+    return pszEnd - psz;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrNCat.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrNCat.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrNCat.c	(revision 2)
@@ -0,0 +1,57 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrNCat.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb)
+{
+    char ch;
+    char *pszDst = psz1;
+
+    while (*pszDst != '\0')
+        pszDst++;
+    while (cb-- > 0)
+    {
+        ch = *psz2++;
+        if (!ch)
+            break;
+        *pszDst++ = ch;
+    }
+    *pszDst = '\0';
+
+    return psz1;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrNComp.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrNComp.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrNComp.c	(revision 2)
@@ -0,0 +1,54 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrNComp.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(int) kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cb)
+{
+    while (cb-- > 0)
+    {
+        char ch1 = *psz1;
+        char ch2 = *psz2;
+        if (ch1 != ch2)
+            return ch1 > ch2 ? 1 : -1;
+        if (!ch1)
+            break;
+        psz1++;
+        psz2++;
+    }
+    return 0;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrNICompAscii.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrNICompAscii.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrNICompAscii.c	(revision 2)
@@ -0,0 +1,61 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrNICompAscii.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(int) kHlpStrNICompAscii(const char *psz1, const char *psz2, KSIZE cb)
+{
+    while (cb-- > 0)
+    {
+        char ch1 = *psz1;
+        char ch2 = *psz2;
+        if (ch1 != ch2)
+        {
+            if (ch1 <= 'Z' && ch1 >= 'A')
+                ch1 += 'a' - 'A';
+            if (ch2 <= 'Z' && ch2 >= 'A')
+                ch2 += 'a' - 'A';
+            if (ch1 != ch2)
+                return ch1 > ch2 ? 1 : -1;
+        }
+        if (!ch1)
+            break;
+        psz1++;
+        psz2++;
+    }
+    return 0;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrNIPCompAscii.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrNIPCompAscii.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrNIPCompAscii.c	(revision 2)
@@ -0,0 +1,63 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrNIPCompAscii.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrNIPCompAscii(const char *psz1, const char *psz2, KSIZE cb)
+{
+    while (cb-- > 0)
+    {
+        char ch1 = *psz1;
+        char ch2 = *psz2;
+        if (ch1 != ch2)
+        {
+            if (ch1 <= 'Z' && ch1 >= 'A')
+                ch1 += 'a' - 'A';
+            if (ch2 <= 'Z' && ch2 >= 'A')
+                ch2 += 'a' - 'A';
+            if (ch1 != ch2)
+                return (char *)psz1;
+        }
+        if (!ch1)
+            break;
+        psz1++;
+        psz2++;
+    }
+    return NULL;
+}
+
+
+
Index: /trunk/kHlp/Generic/kHlpStrNLen.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrNLen.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrNLen.c	(revision 2)
@@ -0,0 +1,46 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrNLen.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(KSIZE) kHlpStrNLen(const char *psz, KSIZE cchMax)
+{
+    const char *pszEnd = psz;
+    while (cchMax-- > 0 && *pszEnd)
+        pszEnd++;
+    return pszEnd - psz;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrNPCat.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrNPCat.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrNPCat.c	(revision 2)
@@ -0,0 +1,56 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrNPCat.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrNPCat(char *pszDst, const char *pszSrc, KSIZE cb)
+{
+    char ch;
+
+    while (*pszDst != '\0')
+        pszDst++;
+    while (cb-- > 0)
+    {
+        ch = *pszSrc++;
+        if (!ch)
+            break;
+        *pszDst++ = ch;
+    }
+    *pszDst = '\0';
+
+    return pszDst;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrNPComp.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrNPComp.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrNPComp.c	(revision 2)
@@ -0,0 +1,55 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrNPComp.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrNPComp(const char *psz1, const char *psz2, KSIZE cb)
+{
+    while (cb-- > 0)
+    {
+        char ch1 = *psz1;
+        char ch2 = *psz2;
+        if (ch1 != ch2)
+            return (char *)psz1;
+        if (!ch1)
+            break;
+        psz1++;
+        psz2++;
+    }
+    return NULL;
+}
+
+
Index: /trunk/kHlp/Generic/kHlpStrPCat.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrPCat.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrPCat.c	(revision 2)
@@ -0,0 +1,53 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrPCat.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrPCat(char *pszDst, const char *psz2)
+{
+    char ch;
+
+    while (*pszDst != '\0')
+        pszDst++;
+    do
+    {
+        ch = *psz2++;
+        *pszDst++ = ch;
+    } while (ch != '\0');
+
+    return pszDst - 1;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrPComp.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrPComp.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrPComp.c	(revision 2)
@@ -0,0 +1,55 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrPComp.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrPComp(const char *psz1, const char *psz2)
+{
+    for (;;)
+    {
+        char ch1 = *psz1;
+        char ch2 = *psz2;
+        if (ch1 != ch2)
+            return (char *)psz1;
+        if (!ch1)
+            return NULL;
+        psz1++;
+        psz2++;
+    }
+}
+
+
+
Index: /trunk/kHlp/Generic/kHlpStrPCopy.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrPCopy.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrPCopy.c	(revision 2)
@@ -0,0 +1,47 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrPCopy.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrPCopy(char *pszDst, const char *pszSrc)
+{
+    char ch;
+    do
+        *pszDst++ = ch = *pszSrc;
+    while (ch);
+    return pszDst - 1;
+}
+
Index: /trunk/kHlp/Generic/kHlpStrRChr.c
===================================================================
--- /trunk/kHlp/Generic/kHlpStrRChr.c	(revision 2)
+++ /trunk/kHlp/Generic/kHlpStrRChr.c	(revision 2)
@@ -0,0 +1,61 @@
+/* $Id$ */
+/** @file
+ * kHlpString - kHlpStrRChr.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kHlpString.h>
+
+
+KHLP_DECL(char *) kHlpStrRChr(const char *psz, int ch)
+{
+    char *pszLast;
+
+    if (!ch)
+    {
+        while (*psz)
+            psz++;
+        return (char *)psz;
+    }
+
+    pszLast = NULL;
+    for (;;)
+    {
+        int chCur = *psz;
+        if (chCur == ch)
+            pszLast = (char *)psz;
+        else if (!chCur)
+            return pszLast;
+        psz++;
+    }
+}
+
Index: /trunk/kHlp/Makefile.kmk
===================================================================
--- /trunk/kHlp/Makefile.kmk	(revision 2)
+++ /trunk/kHlp/Makefile.kmk	(revision 2)
@@ -0,0 +1,116 @@
+# $Id$
+## @file
+# kHlp - The Helper API, sub-makefile.
+#
+
+#
+# Copyright (c) 2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kStuff 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+DEPTH ?= ../..
+SUB_DEPTH = ..
+include $(PATH_KBUILD)/subheader.kmk
+
+#
+# kHlpBaseStatic
+#
+LIBRARIES += kHlpBareStatic
+kHlpBareStatic_TEMPLATE = kStuffLIB
+kHlpBareStatic_SOURCES = \
+	Generic/kHlpMemChr.c \
+	Generic/kHlpMemComp.c \
+	Generic/kHlpMemPComp.c \
+	Generic/kHlpMemICompAscii.c \
+	Generic/kHlpMemCopy.c \
+	Generic/kHlpMemPCopy.c \
+	Generic/kHlpMemMove.c \
+	Generic/kHlpMemPMove.c \
+	Generic/kHlpMemSet.c \
+	Generic/kHlpMemPSet.c \
+	Generic/kHlpStrCat.c \
+	Generic/kHlpStrPCat.c \
+	Generic/kHlpStrNCat.c \
+	Generic/kHlpStrNPCat.c \
+	Generic/kHlpStrChr.c \
+	Generic/kHlpStrRChr.c \
+	Generic/kHlpStrComp.c \
+	Generic/kHlpStrPComp.c \
+	Generic/kHlpStrNComp.c \
+	Generic/kHlpStrNPComp.c \
+	Generic/kHlpStrICompAscii.c \
+	Generic/kHlpStrIPCompAscii.c \
+	Generic/kHlpStrNICompAscii.c \
+	Generic/kHlpStrNIPCompAscii.c \
+	Generic/kHlpStrCopy.c \
+	Generic/kHlpStrPCopy.c \
+	Generic/kHlpStrLen.c \
+	Generic/kHlpStrNLen.c \
+	Generic/kHlpInt2Ascii.c \
+	\
+    Generic/kHlpGetEnvUZ.c \
+	\
+	Generic/kHlpGetExt.c \
+	Generic/kHlpGetFilename.c \
+	Generic/kHlpIsFilenameOnly.c \
+	\
+	Generic/kHlpPage.c \
+	\
+	Bare/kHlpBareAssert.c \
+	Bare/kHlpBareHeap.c \
+	Bare/kHlpBareEnv.c \
+	Bare/kHlpBareProcess.c \
+	Bare/kHlpBareThread.c \
+
+#
+# kCrtStatic
+#
+LIBRARIES += kHlpCRTStatic
+kHlpCRTStatic_TEMPLATE = kStuffLIB
+kHlpCRTStatic_SOURCES = \
+	Generic/kHlpMemPComp.c \
+	Generic/kHlpMemICompAscii.c \
+	Generic/kHlpStrPCat.c \
+	Generic/kHlpStrNPCat.c \
+	Generic/kHlpStrPComp.c \
+	Generic/kHlpStrNPComp.c \
+	Generic/kHlpStrICompAscii.c \
+	Generic/kHlpStrIPCompAscii.c \
+	Generic/kHlpStrNICompAscii.c \
+	Generic/kHlpStrNIPCompAscii.c \
+	Generic/kHlpStrPCopy.c \
+	Generic/kHlpStrNLen.c \
+	Generic/kHlpInt2Ascii.c \
+	\
+    Generic/kHlpGetEnvUZ.c \
+	\
+	Generic/kHlpGetExt.c \
+	Generic/kHlpGetFilename.c \
+	Generic/kHlpIsFilenameOnly.c \
+	\
+	Generic/kHlpPage.c \
+	\
+	CRT/kHlpCRTAlloc.cpp \
+	CRT/kHlpCRTEnv.cpp \
+	CRT/kHlpCRTString.cpp \
+
+
+# Generate the rules
+include $(PATH_KBUILD)/subfooter.kmk
+
Index: /trunk/kLdr/Doxyfile
===================================================================
--- /trunk/kLdr/Doxyfile	(revision 2)
+++ /trunk/kLdr/Doxyfile	(revision 2)
@@ -0,0 +1,1252 @@
+# Doxyfile 1.5.0
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = kLdr
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = YES
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  =
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS          = *.c *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = tst*
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             = tg
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.  Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.  The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.  This is useful
+# if you want to understand what is going on.  On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#   TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#   TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
Index: /trunk/kLdr/Makefile.kmk
===================================================================
--- /trunk/kLdr/Makefile.kmk	(revision 2)
+++ /trunk/kLdr/Makefile.kmk	(revision 2)
@@ -0,0 +1,220 @@
+# $Id$
+## @file
+# kLdr - The Dynamic Loader, sub-makefile.
+#
+
+#
+# Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kStuff 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+DEPTH ?= ../..
+SUB_DEPTH = ..
+include $(PATH_KBUILD)/subheader.kmk
+
+#todo: include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
+
+#
+# Template for testcases.
+#
+TEMPLATE_TST = Testcase template
+ifeq ($(BUILD_TARGET),win)
+ ifeq ($(BUILD_TARGET_ARCH), x86)
+  TEMPLATE_TST_TOOL = VCC70
+  TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD
+  TEMPLATE_TST_LIBS = $(PATH_TOOL_VCC70_LIB)/msvcrt.lib
+ else
+  TEMPLATE_TST_TOOL = VCC80AMD64
+  TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD
+  TEMPLATE_TST_LIBS = $(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib
+ endif
+ TEMPLATE_TST_CFLAGS.release = -O2
+ TEMPLATE_TST_ASFLAGS = -f win
+ TEMPLATE_TST_DEFS = __WIN__
+ TEMPLATE_TST_SDKS = WINPSDK W2K3DDK
+
+else
+ ifeq ($(BUILD_TARGET),os2)
+  TEMPLATE_TST_TOOL = GCC3OMF
+  TEMPLATE_TST_ASFLAGS = -f obj
+  TEMPLATE_TST_LIBS = os2 gcc end
+ else ifeq ($(BUILD_TARGET),darwin)
+  TEMPLATE_TST_TOOL = GCC4MACHO
+  TEMPLATE_TST_ASFLAGS = -f macho
+  TEMPLATE_TST_LIBS = #os2 gcc end
+ else
+  TEMPLATE_TST_TOOL = GCC3
+  TEMPLATE_TST_ASFLAGS = -f elf
+  TEMPLATE_TST_LIBS = gcc
+ endif
+ TEMPLATE_TST_CFLAGS = -Wall -pedantic -g -std=gnu99
+ TEMPLATE_TST_CFLAGS.release = -O2
+ TEMPLATE_TST_LDFLAGS =
+endif
+TEMPLATE_TST_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include
+
+
+#
+# The kLdr DLL.
+#
+DLLS += kLdr
+kLdr_ASTOOL = NASM
+ifeq ($(BUILD_TARGET),win)
+ ifeq ($(BUILD_TARGET_ARCH),x86)
+  kLdr_TOOL = VCC70
+  kLdr_CFLAGS = -W3 -Zl -ML
+  kLdr_LDFLAGS = -Entry:DllMain@12 -Debug
+  kLdr_LIBS = \
+   	$(PATH_TOOL_VCC70_LIB)/LIBC.lib \
+	$(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib
+ else
+  kLdr_TOOL = VCC80AMD64
+  kLdr_ASTOOL = YASM
+  kLdr_CFLAGS = -W3 -Zl -MT
+  kLdr_LDFLAGS = -Entry:DllMain -Debug
+  kLdr_LIBS = \
+   	$(PATH_TOOL_VCC80AMD64_LIB)/LIBCMT.lib \
+	$(PATH_SDK_W2K3DDKAMD64_LIB)/ntdll.lib
+ endif
+ kLdr_ASFLAGS = -f win
+ kLdr_DEFS = __WIN__
+ kLdr_SDKS.x86 = WIN32SDK W2K3DDKX86
+ kLdr_SDKS.amd64 = WIN64SDK W2K3DDKAMD64
+else
+ ifeq ($(BUILD_TARGET),os2)
+  kLdr_TOOL = GCC3OMF
+  kLdr_ASFLAGS = -f obj
+  kLdr_LIBS = os2 gcc end
+ else ifeq ($(BUILD_TARGET),darwin)
+  kLdr_TOOL = GCC4MACHO
+  kLdr_ASFLAGS = -f macho
+  kLdr_LIBS = #os2 gcc end
+ else
+  kLdr_TOOL = GCC3
+  kLdr_ASFLAGS = -f elf
+  kLdr_LIBS = gcc
+ endif
+ kLdr_CFLAGS = -Wall -pedantic
+ kLdr_LDFLAGS = -nostdlib
+endif
+kLdr_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include
+kLdr_SOURCES = \
+	kLdr.c \
+	kLdrDyld.c \
+	kLdrDyldFind.c \
+	kLdrDyldMod.c \
+	kLdrDyldOS.c \
+	kLdrDyLdSem.c \
+	kLdrMod.c \
+	kLdrModLX.c \
+	kLdrModMachO.c \
+	kLdrModNative.c \
+	kLdrModPE.c
+kLdr_SOURCES.os2 = \
+	kLdr-os2.def \
+	kLdr-os2.c \
+	kLdrA-os2.asm
+kLdr_SOURCES.win = \
+	kLdr-win.def \
+	kLdr-win.c
+kLdr_LIBS += \
+	$(PATH_LIB)/kRdrStatic$(SUFF_LIB) \
+	$(PATH_LIB)/kCpuStatic$(SUFF_LIB) \
+	$(PATH_LIB)/kHlpBareStatic$(SUFF_LIB) \
+	$(PATH_LIB)/kErrStatic$(SUFF_LIB)
+
+#
+# A static edition of kLdr.
+#
+LIBRARIES += kLdrStatic
+kLdrStatic_TEMPLATE = kStuffLIB
+kLdrStatic_SDKS.win = WINPSDK W2K3DDK
+kLdrStatic_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include
+kLdrStatic_DEFS.darwin = __DARWIN__
+kLdrStatic_DEFS.os2 = __OS2__
+kLdrStatic_DEFS.win = __WIN__
+kLdrStatic_SOURCES = $(kLdr_SOURCES)
+
+#
+# The OS/2 stub program.
+#
+PROGRAMS.os2 = kLdrExeStub-os2
+kLdrExeStub-os2_TOOL = GCC3OMF
+kLdrExeStub-os2_ASTOOL = NASM
+kLdrExeStub-os2_ASFLAGS = -f obj
+#kLdrExeStub-os2_LDFLAGS = -nostdlib
+kLdrExeStub-os2_LDFLAGS = -nostdlib -Zstack 64
+kLdrExeStub-os2_LIBS = $(TARGET_kLdr)
+#kLdrExeStub-os2_SOURCES = kLdrExeStub-os2.asm
+kLdrExeStub-os2_SOURCES =  kLdrExeStub-os2A.asm kLdrExeStub-os2.c
+
+#
+# The Windows stub program.
+#
+PROGRAMS.win = kLdrExeStub-win
+kLdrExeStub-win_TOOL.win.x86 = VCC70
+kLdrExeStub-win_TOOL.win.amd64 = VCC80AMD64
+kLdrExeStub-win_SDKS.x86 = WIN32SDK
+kLdrExeStub-win_SDKS.amd64 = WIN64SDK
+kLdrExeStub-win_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include
+kLdrExeStub-win_DEFS = __WIN__
+kLdrExeStub-win_CFLAGS = -W3 -Zl
+kLdrExeStub-win_CFLAGS.debug = -Zi
+kLdrExeStub-win_LDFLAGS = -Entry:WindowsMain -SubSystem:Console -FIXED:NO
+kLdrExeStub-win_LIBS = $(TARGET_kLdr:.dll=.lib)
+kLdrExeStub-win_SOURCES = kLdrExeStub-win.c
+
+
+##
+## The (stub) utility.
+##
+#PROGRAMS = kLdrUtil
+
+
+#
+# Heap testcase.
+#
+#PROGRAMS += tstkLdrHeap
+tstkLdrHeap_TEMPLATE = TST
+tstkLdrHeap_SOURCES = \
+	tstkLdrHeap.c \
+	kHlp.c \
+	kHlpHeap.c \
+	kHlpMem.c \
+	kHlpPath.c \
+	kHlpSem.c \
+	kHlpStr.c \
+
+#
+# Heap testcase.
+#
+PROGRAMS += tstkLdrMod
+tstkLdrMod_TEMPLATE = TST
+tstkLdrMod_SOURCES = \
+	tstkLdrMod.c
+ifeq ($(BUILD_TARGET),win)
+tstkLdrMod_LIBS = $(TARGET_kLdr:.dll=.lib)
+else
+tstkLdrMod_LIBS = $(TARGET_kLdr)
+endif
+
+
+# Generate rules.
+include $(PATH_KBUILD)/subfooter.kmk
+
Index: /trunk/kLdr/kLdr-os2.c
===================================================================
--- /trunk/kLdr/kLdr-os2.c	(revision 2)
+++ /trunk/kLdr/kLdr-os2.c	(revision 2)
@@ -0,0 +1,68 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader, OS/2 Specifics.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define INCL_BASE
+#include <os2.h>
+
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+
+/**
+ * The DLL main function.
+ *
+ * @returns TRUE / FALSE.
+ * @param   hmod        The dll handle.
+ * @param   fFlags      Flags.
+ */
+ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlags)
+{
+    switch (fFlags)
+    {
+        case 0:
+        {
+            int rc = kldrInit();
+            return rc == 0;
+        }
+
+        case 1:
+            kldrTerm();
+            return TRUE;
+
+        default:
+            return FALSE;
+    }
+}
+
Index: /trunk/kLdr/kLdr-os2.def
===================================================================
--- /trunk/kLdr/kLdr-os2.def	(revision 2)
+++ /trunk/kLdr/kLdr-os2.def	(revision 2)
@@ -0,0 +1,118 @@
+; $Id$
+;; @file
+; kLdr - The Dynamic Loader, OS/2 Linker Definition File.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; In addition to the permissions in the GNU Lesser General Public
+; License, you are granted unlimited permission to link the compiled
+; version of this file into combinations with other programs, and to
+; distribute those combinations without any restriction coming from
+; the use of this file.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA
+;
+
+
+LIBRARY kLdr INITINSTANCE TERMINSTANCE
+DATA MULTIPLE
+EXPORTS
+    ; The file reader API
+    _kRdrAddProvider
+    _kRdrOpen
+    _kRdrClose
+    _kRdrRead
+    _kRdrAllMap
+    _kRdrAllUnmap
+    _kRdrSize
+    _kRdrTell
+    _kRdrName
+    _kRdrPageSize
+    _kRdrMap
+    _kRdrRefresh
+    _kRdrProtect
+    _kRdrUnmap
+    _kRdrDone
+
+    ; The module interpreter API
+    _kLdrModOpen
+    _kLdrModOpenFromRdr
+    _kLdrModOpenNative
+    _kLdrModOpenNativeByHandle
+    _kLdrModClose
+    _kLdrModQuerySymbol
+    _kLdrModEnumSymbols
+    _kLdrModGetImport
+    _kLdrModNumberOfImports
+    _kLdrModCanExecuteOn
+    _kLdrModGetStackInfo
+    _kLdrModQueryMainEntrypoint
+    _kLdrModEnumDbgInfo
+    _kLdrModHasDbgInfo
+    _kLdrModMap
+    _kLdrModUnmap
+    _kLdrModAllocTLS
+    _kLdrModFreeTLS
+    _kLdrModReload
+    _kLdrModFixupMapping
+    _kLdrModCallInit
+    _kLdrModCallTerm
+    _kLdrModCallThread
+    _kLdrModSize
+    _kLdrModGetBits
+    _kLdrModRelocateBits
+
+    ; Process Bootstrapping
+    _kLdrDyldLoadExe
+
+    ; Dynamic loading
+    _kLdrDyldLoad
+    _kLdrDyldUnload
+    _kLdrDyldFindByName
+    _kLdrDyldFindByAddress
+    _kLdrDyldGetName
+    _kLdrDyldGetFilename
+    _kLdrDyldQuerySymbol
+
+
+    ; OS/2 API wrappers:
+;    kLdrLoadModule
+;    kLdrFreeModule
+;    kLdrQueryModuleHandle
+;    kLdrQueryModuleName
+;    kLdrQueryProcAddr
+;    kLdrQueryProcType
+;    kLdrQueryModFromEIP
+;    kLdrReplaceModule
+;    kLdrGetResource
+;    kLdrFreeResource
+;    kLdrQueryResourceSize
+
+    ; dlfcn API wrappers:
+;    _kLdrDlOpen
+;    _kLdrDlClose
+;    _kLdrDlError
+;    _kLdrDlSym
+;    _kLdrDlFunc
+
+    ; Error APIs:
+    _kErrStr
+
+
Index: /trunk/kLdr/kLdr-win.c
===================================================================
--- /trunk/kLdr/kLdr-win.c	(revision 2)
+++ /trunk/kLdr/kLdr-win.c	(revision 2)
@@ -0,0 +1,79 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader, Windows Specifics.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <Windows.h>
+
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+
+/**
+ * The DLL main function.
+ *
+ * @returns TRUE / FALSE.
+ * @param   hDllHandle  The dll handle.
+ * @param   dwReason    The reason we're being called.
+ * @param   lpReserved  Reserved.
+ */
+BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)
+{
+    switch (dwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+        {
+            int rc = kldrInit();
+            return rc == 0;
+        }
+
+        case DLL_PROCESS_DETACH:
+            kldrTerm();
+            return TRUE;
+
+        case DLL_THREAD_ATTACH:
+        {
+            //int rc = kLdrDyldThreadAttach();
+            //return rc == 0;
+            return TRUE;
+        }
+
+        case DLL_THREAD_DETACH:
+            //kLdrDyldThreadDetach();
+            return TRUE;
+
+        default:
+            return FALSE;
+    }
+}
+
Index: /trunk/kLdr/kLdr-win.def
===================================================================
--- /trunk/kLdr/kLdr-win.def	(revision 2)
+++ /trunk/kLdr/kLdr-win.def	(revision 2)
@@ -0,0 +1,116 @@
+; $Id$
+;; @file
+; kLdr - The Dynamic Loader, Windows Linker Definition File.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; In addition to the permissions in the GNU Lesser General Public
+; License, you are granted unlimited permission to link the compiled
+; version of this file into combinations with other programs, and to
+; distribute those combinations without any restriction coming from
+; the use of this file.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA
+;
+
+
+LIBRARY kLdr
+EXPORTS
+    ; The file reader API
+    kRdrAddProvider
+    kRdrOpen
+    kRdrClose
+    kRdrRead
+    kRdrAllMap
+    kRdrAllUnmap
+    kRdrSize
+    kRdrTell
+    kRdrName
+    kRdrPageSize
+    kRdrMap
+    kRdrRefresh
+    kRdrProtect
+    kRdrUnmap
+    kRdrDone
+
+    ; The module interpreter API
+    kLdrModOpen
+    kLdrModOpenFromRdr
+    kLdrModOpenNative
+    kLdrModOpenNativeByHandle
+    kLdrModClose
+    kLdrModQuerySymbol
+    kLdrModEnumSymbols
+    kLdrModGetImport
+    kLdrModNumberOfImports
+    kLdrModCanExecuteOn
+    kLdrModGetStackInfo
+    kLdrModQueryMainEntrypoint
+    kLdrModEnumDbgInfo
+    kLdrModHasDbgInfo
+    kLdrModMap
+    kLdrModUnmap
+    kLdrModAllocTLS
+    kLdrModFreeTLS
+    kLdrModReload
+    kLdrModFixupMapping
+    kLdrModCallInit
+    kLdrModCallTerm
+    kLdrModCallThread
+    kLdrModSize
+    kLdrModGetBits
+    kLdrModRelocateBits
+
+    ; Process Bootstrapping
+    kLdrDyldLoadExe
+
+    ; Dynamic loading
+    kLdrDyldLoad
+    kLdrDyldUnload
+    kLdrDyldFindByName
+    kLdrDyldFindByAddress
+    kLdrDyldGetName
+    kLdrDyldGetFilename
+    kLdrDyldQuerySymbol
+
+
+    ; OS/2 API wrappers:
+;    kLdrLoadModule
+;    kLdrFreeModule
+;    kLdrQueryModuleHandle
+;    kLdrQueryModuleName
+;    kLdrQueryProcAddr
+;    kLdrQueryProcType
+;    kLdrQueryModFromEIP
+;    kLdrReplaceModule
+;    kLdrGetResource
+;    kLdrFreeResource
+;    kLdrQueryResourceSize
+
+    ; dlfcn API wrappers:
+;    _kLdrDlOpen
+;    _kLdrDlClose
+;    _kLdrDlError
+;    _kLdrDlSym
+;    _kLdrDlFunc
+
+    ; Error APIs:
+    kErrName
+
Index: /trunk/kLdr/kLdr.c
===================================================================
--- /trunk/kLdr/kLdr.c	(revision 2)
+++ /trunk/kLdr/kLdr.c	(revision 2)
@@ -0,0 +1,147 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+/** @mainpage   kLdr - The Dynamic Loader
+ *
+ * The purpose of kLdr is to provide a generic interface for querying
+ * information about and loading executable image modules.
+ *
+ * kLdr defines the term executable image to include all kinds of files that contains
+ * binary code that can be executed on a CPU - linker objects (OBJs/Os), shared
+ * objects (SOs), dynamic link libraries (DLLs), executables (EXEs), and all kinds
+ * of kernel modules / device drivers (SYSs).
+ *
+ * kLdr provides two types of services:
+ *      -# Inspect or/and load individual modules (kLdrMod).
+ *      -# Work as a dynamic loader - construct and maintain an address space (kLdrDy).
+ *
+ * The kLdrMod API works on KLDRMOD structures where all the internals are exposed, while
+ * the kLdrDy API works opque KLDRDY structures. KLDRDY are in reality simple wrappers
+ * around KLDRMOD with some extra linking and attributes.
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** Flag indicating whether we've initialized the loader or not.
+ *
+ * 0 if not initialized.
+ * -1 if we're initializing or terminating.
+ * 1 if we've successfully initialized it.
+ * -2 if initialization failed.
+ */
+static int volatile g_fInitialized;
+
+
+
+/**
+ * Initializes the loader.
+ * @returns 0 on success, non-zero OS status code on failure.
+ */
+int kldrInit(void)
+{
+    int rc;
+
+    /* check we're already good. */
+    if (g_fInitialized == 1)
+        return 0;
+
+    /* a tiny serialization effort. */
+    for (;;)
+    {
+        if (g_fInitialized == 1)
+            return 0;
+        if (g_fInitialized == -2)
+            return -1;
+        /** @todo atomic test and set if we care. */
+        if (g_fInitialized == 0)
+        {
+            g_fInitialized = -1;
+            break;
+        }
+        kHlpSleep(1);
+    }
+
+    /*
+     * Do the initialization.
+     */
+    rc = kHlpHeapInit();
+    if (!rc)
+    {
+        rc = kLdrDyldSemInit();
+        if (!rc)
+        {
+            rc = kldrDyldInit();
+            if (!rc)
+            {
+                g_fInitialized = 1;
+                return 0;
+            }
+            kLdrDyldSemTerm();
+        }
+        kHlpHeapTerm();
+    }
+    g_fInitialized = -2;
+    return rc;
+}
+
+
+/**
+ * Terminates the loader.
+ */
+void kldrTerm(void)
+{
+    /* can't terminate unless it's initialized. */
+    if (g_fInitialized != 1)
+        return;
+    g_fInitialized = -1;
+
+    /*
+     * Do the termination.
+     */
+    kLdrDyldSemTerm();
+    kHlpHeapTerm();
+
+    /* done */
+    g_fInitialized = 0;
+}
+
Index: /trunk/kLdr/kLdrA-os2.asm
===================================================================
--- /trunk/kLdr/kLdrA-os2.asm	(revision 2)
+++ /trunk/kLdr/kLdrA-os2.asm	(revision 2)
@@ -0,0 +1,68 @@
+; $Id$
+;; @file
+; kLdr - The Dynamic Loader, OS/2 Assembly Helpers.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; In addition to the permissions in the GNU Lesser General Public
+; License, you are granted unlimited permission to link the compiled
+; version of this file into combinations with other programs, and to
+; distribute those combinations without any restriction coming from
+; the use of this file.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA
+;
+
+segment TEXT32 public align=16 CLASS=CODE use32
+
+;
+; _DLL_InitTerm
+;
+..start:
+extern _DLL_InitTerm
+    jmp _DLL_InitTerm
+
+
+;
+; kLdrLoadExe wrapper which loads the bootstrap stack.
+;
+global _kLdrDyldLoadExe
+_kLdrDyldLoadExe:
+    push    ebp
+    mov     ebp, esp
+
+    ; switch stack.
+;    extern _abStack
+;    lea     esp, [_abStack + 8192 - 4]
+    push    dword [ebp + 8 + 20]
+    push    dword [ebp + 8 + 16]
+    push    dword [ebp + 8 + 12]
+    push    dword [ebp + 8 +  8]
+
+    ; call worker on the new stack.
+    extern  _kldrDyldLoadExe
+    call    _kldrDyldLoadExe
+
+    ; we shouldn't return!
+we_re_not_supposed_to_get_here:
+    int3
+    int3
+    jmp short we_re_not_supposed_to_get_here
+
Index: /trunk/kLdr/kLdrDyld.c
===================================================================
--- /trunk/kLdr/kLdrDyld.c	(revision 2)
+++ /trunk/kLdr/kLdrDyld.c	(revision 2)
@@ -0,0 +1,1511 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRDYLD_STRICT
+ * Define KLDRDYLD_STRICT to enabled strict checks in kLdrDyld. */
+#define KLDRDYLD_STRICT 1
+
+/** @def KLDRDYLD_ASSERT
+ * Assert that an expression is true when KLDRDYLD_STRICT is defined.
+ */
+#ifdef KLDRDYLD_STRICT
+# define KLDRDYLD_ASSERT(expr)  kHlpAssert(expr)
+#else
+# define KLDRDYLD_ASSERT(expr)  do {} while (0)
+#endif
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** Pointer to the executable module.
+ * (This is exported, so no prefix.) */
+PKLDRDYLDMOD    kLdrDyldExe = NULL;
+/** Pointer to the head module (the executable).
+ * (This is exported, so no prefix.) */
+PKLDRDYLDMOD    kLdrDyldHead = NULL;
+/** Pointer to the tail module.
+ * (This is exported, so no prefix.) */
+PKLDRDYLDMOD    kLdrDyldTail = NULL;
+/** Pointer to the head module of the initialization list.
+ * The outermost load call will pop elements from this list in LIFO order (i.e.
+ * from the tail). The list is only used during non-recursive initialization
+ * and may therefore share the pNext/pPrev members with the termination list
+ * since we don't push a module onto the termination list untill it has been
+ * successfully initialized. */
+PKLDRDYLDMOD    g_pkLdrDyldInitHead;
+/** Pointer to the tail module of the initalization list.*/
+PKLDRDYLDMOD    g_pkLdrDyldInitTail;
+/** Pointer to the head module of the termination order list.
+ * This is a LIFO just like the the init list. */
+PKLDRDYLDMOD    g_pkLdrDyldTermHead;
+/** Pointer to the tail module of the termination order list. */
+PKLDRDYLDMOD    g_pkLdrDyldTermTail;
+/** Pointer to the head module of the bind order list.
+ * The modules in this list makes up the global namespace used when binding symbol unix fashion. */
+PKLDRDYLDMOD    g_pkLdrDyldBindHead;
+/** Pointer to the tail module of the bind order list. */
+PKLDRDYLDMOD    g_pkLdrDyldBindTail;
+
+/** Flag indicating bootstrap time.
+ * When set the error behaviour changes. Any kind of serious failure
+ * is fatal and will terminate the process. */
+int             g_fBootstrapping;
+/** The global error buffer. */
+char            g_szkLdrDyldError[1024];
+
+/** The default flags. */
+KU32            kLdrDyldFlags = 0;
+/** The default search method. */
+KLDRDYLDSEARCH  kLdrDyldSearch = KLDRDYLD_SEARCH_HOST;
+
+
+/** @name The main stack.
+ * @{ */
+/** Indicates that the other MainStack globals have been filled in. */
+unsigned        g_fkLdrDyldDoneMainStack = 0;
+/** Whether the stack was allocated seperatly or was part of the executable. */
+unsigned        g_fkLdrDyldMainStackAllocated = 0;
+/** Pointer to the main stack object. */
+void           *g_pvkLdrDyldMainStack = NULL;
+/** The size of the main stack object. */
+KSIZE           g_cbkLdrDyldMainStack = 0;
+/** @} */
+
+
+/** The load stack.
+ * This contains frames with modules affected by active loads.
+ *
+ * Each kLdrDyldLoad and kLdrDyldLoadExe call will create a new stack frame containing
+ * all the modules involved in the operation. The modules will be ordered in recursive
+ * init order within the frame.
+ */
+static PPKLDRDYLDMOD    g_papStackMods;
+/** The number of used entries in the g_papStackMods array. */
+static KU32             g_cStackMods;
+/** The number of entries allocated for the g_papStackMods array. */
+static KU32             g_cStackModsAllocated;
+/** Number of active load calls. */
+static KU32             g_cActiveLoadCalls;
+/** Number of active unload calls. */
+static KU32             g_cActiveUnloadCalls;
+/** Total number of load calls. */
+static KU32             g_cTotalLoadCalls;
+/** Total mumber of unload calls. */
+static KU32             g_cTotalUnloadCalls;
+/** Boolean flag indicating that GC is active. */
+static KU32             g_fActiveGC;
+
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+/** @name API worker routines.
+ * @internal
+ * @{ */
+void       kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack);
+static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                          unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr);
+static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix,
+                           KLDRDYLDSEARCH enmSearch, unsigned fFlags);
+static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
+                                       KLDRDYLDSEARCH enmSearch, unsigned fFlags);
+static int kldrDyldDoUnload(PKLDRDYLDMOD pMod);
+static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                              unsigned fFlags, PPKLDRDYLDMOD ppMod);
+static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment);
+static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName);
+static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename);
+static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind);
+/** @} */
+
+/** @name Misc load/unload workers
+ * @internal
+ * @{
+ */
+static void         kldrDyldDoModuleTerminationAndGarabageCollection(void);
+/** @} */
+
+/** @name The load stack.
+ * @internal
+ * @{ */
+static KU32         kldrDyldStackNewFrame(PKLDRDYLDMOD pMod);
+static int          kldrDyldStackAddModule(PKLDRDYLDMOD pMod);
+static int          kldrDyldStackFrameCompleted(void);
+static void         kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc);
+static void         kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc);
+/** @} */
+
+static int          kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr);
+
+
+
+/**
+ * Initialize the dynamic loader.
+ */
+int kldrDyldInit(void)
+{
+    kLdrDyldHead = kLdrDyldTail = NULL;
+    g_pkLdrDyldTermHead = g_pkLdrDyldTermTail = NULL;
+    g_pkLdrDyldBindHead = g_pkLdrDyldBindTail = NULL;
+    kLdrDyldFlags = 0;
+    g_szkLdrDyldError[0] = '\0';
+
+    g_fkLdrDyldDoneMainStack = 0;
+    g_fkLdrDyldMainStackAllocated = 0;
+    g_pvkLdrDyldMainStack = NULL;
+    g_cbkLdrDyldMainStack = 0;
+
+    return kldrDyldFindInit();
+}
+
+
+/**
+ * Terminate the dynamic loader.
+ */
+void kldrDyldTerm(void)
+{
+
+}
+
+
+/**
+ * Bootstrap an executable.
+ *
+ * This is called from the executable stub to replace the stub and run the
+ * executable specified in the argument package.
+ *
+ * Since this is boostrap time there isn't anything to return to. So, instead
+ * the process will be terminated upon failure.
+ *
+ * We also have to keep in mind that this function is called on a small, small,
+ * stack and therefore any kind of large stack objects or deep recursions must
+ * be avoided. Since loading the executable will involve more or less all
+ * operations in the loader, this restriction really applies everywhere.
+ *
+ * @param   pArgs       Pointer to the argument package residing in the executable stub.
+ * @param   pvOS        OS specific argument.
+ */
+#ifndef __OS2__  /* kLdrDyldLoadExe is implemented in assembly on OS/2. */
+void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS)
+#else
+void kldrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS)
+#endif
+{
+    void *pvStack;
+    KSIZE  cbStack;
+    PKLDRDYLDMOD pExe;
+    int rc;
+
+    /*
+     * Indicate that we're boostrapping and ensure that initialization was successful.
+     */
+    g_fBootstrapping = 1;
+    rc = kldrInit();
+    if (rc)
+        kldrDyldFailure(rc, "Init failure, rc=%d", rc);
+
+    /*
+     * Validate the argument package.
+     */
+    if (pArgs->fFlags & ~(  KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS
+                          | KLDRYDLD_LOAD_FLAGS_DEEP_SYMBOLS
+                          | KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT
+                          | KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
+        kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad fFlags=%#x", pArgs->fFlags);
+    if (    pArgs->enmSearch <= KLDRDYLD_SEARCH_INVALID
+        ||  pArgs->enmSearch >= KLDRDYLD_SEARCH_END)
+        kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad enmSearch=%d", pArgs->enmSearch);
+
+    /*
+     * Set defaults.
+     */
+    kLdrDyldFlags |= (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT);
+    kLdrDyldSearch = pArgs->enmSearch;
+
+    /** @todo make sense of this default prefix/suffix stuff. */
+    if (pArgs->szDefPrefix[0] != '\0')
+        kHlpMemCopy(kLdrDyldDefPrefix, pArgs->szDefPrefix, K_MIN(sizeof(pArgs->szDefPrefix), sizeof(kLdrDyldDefPrefix)));
+    if (pArgs->szDefSuffix[0] != '\0')
+        kHlpMemCopy(kLdrDyldDefSuffix, pArgs->szDefSuffix, K_MIN(sizeof(pArgs->szDefSuffix), sizeof(kLdrDyldDefSuffix)));
+
+    /** @todo append that path to the one for the specified search method. */
+    /** @todo create a function for doing this, an exposed api preferably. */
+    /* append path */
+    cbStack = sizeof(kLdrDyldLibraryPath) - kHlpStrLen(kLdrDyldLibraryPath); /* borrow cbStack for a itty bit. */
+    kHlpMemCopy(kLdrDyldLibraryPath, pArgs->szLibPath, K_MIN(sizeof(pArgs->szLibPath), cbStack));
+    kLdrDyldLibraryPath[sizeof(kLdrDyldLibraryPath) - 1] = '\0';
+
+    /*
+     * Make sure we own the loader semaphore (necessary for init).
+     */
+    rc = kLdrDyldSemRequest();
+    if (rc)
+        kldrDyldFailure(rc, "Sem req. failure, rc=%d", rc);
+
+    /*
+     * Open and map the executable module before we join paths with kLdrDyldLoad().
+     */
+    rc = kldrDyldFindNewModule(pArgs->szExecutable, NULL, NULL, pArgs->enmSearch,
+                               pArgs->fFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE, &pExe);
+    if (rc)
+        kldrDyldFailure(rc, "Can't find/open the executable '%s', rc=%d", pArgs->szExecutable, rc);
+    rc = kldrDyldModMap(pExe);
+    if (rc)
+        kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc);
+
+    kLdrDyldExe = pExe;
+
+    /*
+     * Query the stack and go to OS specific code to
+     * setup and switch stack. The OS specific code will call us
+     * back at kldrDyldDoLoadExe.
+     */
+    rc = kldrDyldModGetMainStack(pExe, &pvStack, &cbStack);
+    if (rc)
+        kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc);
+    kldrDyldDoLoadExeStackSwitch(pExe, pvStack, cbStack);
+    kldrDyldFailure(-1, "Failed to setup the stack for '%s'.", pExe->pMod->pszFilename);
+}
+
+
+/**
+ * Loads a module into the current process.
+ *
+ * @returns 0 on success, non-zero native OS status code or kLdr status code on failure.
+ * @param   pszDll          The name of the dll to open.
+ * @param   pszPrefix       Prefix to use when searching.
+ * @param   pszSuffix       Suffix to use when searching.
+ * @param   enmSearch       Method to use when locating the module and any modules it may depend on.
+ * @param   fFlags          Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
+ * @param   phMod           Where to store the handle to the loaded module.
+ * @param   pszErr          Where to store extended error information. (optional)
+ * @param   cchErr          The size of the buffer pointed to by pszErr.
+ */
+int     kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                     unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr)
+{
+    int rc;
+
+    /* validate arguments and initialize return values. */
+    if (pszErr && cchErr)
+        *pszErr = '\0';
+    *phMod = NIL_HKLDRMOD;
+    K_VALIDATE_STRING(pszDll);
+    K_VALIDATE_OPTIONAL_STRING(pszPrefix);
+    K_VALIDATE_OPTIONAL_STRING(pszSuffix);
+    K_VALIDATE_ENUM(enmSearch, KLDRDYLD_SEARCH);
+    K_VALIDATE_OPTIONAL_BUFFER(pszErr, cchErr);
+
+    /* get the semaphore and do the job. */
+    rc = kLdrDyldSemRequest();
+    if (!rc)
+    {
+        PKLDRDYLDMOD pMod = NULL;
+        g_cTotalLoadCalls++;
+        g_cActiveLoadCalls++;
+        rc = kldrDyldDoLoad(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod, pszErr, cchErr);
+        g_cActiveLoadCalls--;
+        kldrDyldDoModuleTerminationAndGarabageCollection();
+        kLdrDyldSemRelease();
+        *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
+    }
+    return rc;
+}
+
+
+/**
+ * Unloads a module loaded by kLdrDyldLoad.
+ *
+ * @returns 0 on success, non-zero native OS status code or kLdr status code on failure.
+ * @param   hMod            Module handle.
+ */
+int     kLdrDyldUnload(HKLDRMOD hMod)
+{
+    int rc;
+
+    /* validate */
+    KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
+
+    /* get sem & do work */
+    rc = kLdrDyldSemRequest();
+    if (!rc)
+    {
+        g_cTotalUnloadCalls++;
+        g_cActiveUnloadCalls++;
+        rc = kldrDyldDoUnload(hMod);
+        g_cActiveUnloadCalls--;
+        kldrDyldDoModuleTerminationAndGarabageCollection();
+        kLdrDyldSemRelease();
+    }
+    return rc;
+}
+
+
+/**
+ * Finds a module by name or filename.
+ *
+ * This call does not increase any reference counters and must not be
+ * paired with kLdrDyldUnload() like kLdrDyldLoad().
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND or some I/O error on failure.
+ * @param   pszDll          The name of the dll to look for.
+ * @param   pszPrefix       Prefix than can be used when searching.
+ * @param   pszSuffix       Suffix than can be used when searching.
+ * @param   enmSearch       Method to use when locating the module.
+ * @param   fFlags          Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
+ * @param   phMod           Where to store the handle of the module on success.
+ */
+int     kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                           unsigned fFlags, PHKLDRMOD phMod)
+{
+    int rc;
+
+    /* validate & initialize */
+    *phMod = NIL_HKLDRMOD;
+    K_VALIDATE_STRING(pszDll);
+
+    /* get sem & do work */
+    rc = kLdrDyldSemRequest();
+    if (!rc)
+    {
+        PKLDRDYLDMOD pMod = NULL;
+        rc = kldrDyldDoFindByName(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
+        kLdrDyldSemRelease();
+        *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
+    }
+    return rc;
+}
+
+
+/**
+ * Finds a module by address.
+ *
+ * This call does not increase any reference counters and must not be
+ * paired with kLdrDyldUnload() like kLdrDyldLoad().
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND on failure.
+ * @param   Address         The address believed to be within some module.
+ * @param   phMod           Where to store the module handle on success.
+ * @param   piSegment       Where to store the segment number. (optional)
+ * @param   poffSegment     Where to store the offset into the segment. (optional)
+ */
+int     kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment)
+{
+    int rc;
+
+    /* validate & initialize */
+    *phMod = NIL_HKLDRMOD;
+    if (piSegment)
+        *piSegment = ~(KU32)0;
+    if (poffSegment)
+        *poffSegment = ~(KUPTR)0;
+
+    /* get sem & do work */
+    rc = kLdrDyldSemRequest();
+    if (!rc)
+    {
+        PKLDRDYLDMOD pMod = NULL;
+        rc = kldrDyldDoFindByAddress(Address, &pMod, piSegment, poffSegment);
+        kLdrDyldSemRelease();
+        *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD;
+    }
+    return rc;
+}
+
+
+/**
+ * Gets the module name.
+ *
+ * @returns 0 on success and pszName filled with the name.
+ * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure.
+ * @param   hMod        The module handle.
+ * @param   pszName     Where to put the name.
+ * @param   cchName     The size of the name buffer.
+ * @see kLdrDyldGetFilename
+ */
+int     kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName)
+{
+    int rc;
+
+    /* validate */
+    if (pszName && cchName)
+        *pszName = '\0';
+    KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
+    K_VALIDATE_BUFFER(pszName, cchName);
+
+    /* get sem & do work */
+    rc = kLdrDyldSemRequest();
+    if (!rc)
+    {
+        rc = kldrDyldDoGetName(hMod, pszName, cchName);
+        kLdrDyldSemRelease();
+    }
+    return rc;
+}
+
+
+/**
+ * Gets the module filename.
+ *
+ * @returns 0 on success and pszFilename filled with the name.
+ * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure.
+ * @param   hMod            The module handle.
+ * @param   pszFilename     Where to put the filename.
+ * @param   cchFilename     The size of the filename buffer.
+ * @see kLdrDyldGetName
+ */
+int     kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename)
+{
+    int rc;
+
+    /* validate & initialize */
+    if  (pszFilename && cchFilename);
+        *pszFilename = '\0';
+    KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
+    K_VALIDATE_BUFFER(pszFilename, cchFilename);
+
+    /* get sem & do work */
+    rc = kLdrDyldSemRequest();
+    if (!rc)
+    {
+        rc = kldrDyldDoGetFilename(hMod, pszFilename, cchFilename);
+        kLdrDyldSemRelease();
+    }
+    return rc;
+}
+
+
+/**
+ * Queries the value and type of a symbol.
+ *
+ * @returns 0 on success and pValue and pfKind set.
+ * @returns KERR_INVALID_HANDLE or KLDR_ERR_SYMBOL_NOT_FOUND on failure.
+ * @param   hMod                The module handle.
+ * @param   uSymbolOrdinal      The symbol ordinal. This is ignored if pszSymbolName is non-zero.
+ * @param   pszSymbolName       The symbol name.
+ * @param   pszSymbolVersion    The symbol version. Optional.
+ * @param   pValue              Where to put the symbol value. Optional if pfKind is non-zero.
+ * @param   pfKind              Where to put the symbol kind flags. Optional if pValue is non-zero.
+ */
+int     kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName,
+                            const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind)
+{
+    int rc;
+
+    /* validate & initialize */
+    if (pfKind)
+        *pfKind = 0;
+    if (pValue)
+        *pValue = 0;
+    if (!pfKind && !pValue)
+        return KERR_INVALID_PARAMETER;
+    KLDRDYLD_VALIDATE_HKLDRMOD(hMod);
+    K_VALIDATE_OPTIONAL_STRING(pszSymbolName);
+
+    /* get sem & do work */
+    rc = kLdrDyldSemRequest();
+    if (!rc)
+    {
+        rc = kldrDyldDoQuerySymbol(hMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
+        kLdrDyldSemRelease();
+    }
+    return rc;
+}
+
+
+/**
+ * Worker kLdrDoLoadExe().
+ * Used after we've switch to the final process stack.
+ *
+ * @param   pExe    The executable module.
+ * @internal
+ */
+void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe)
+{
+    int rc;
+
+    /*
+     * Load the executable module with its prerequisites and initialize them.
+     */
+    g_cActiveLoadCalls++;
+    rc = kldrDyldDoLoad2(pExe, NULL, NULL, kLdrDyldSearch, kLdrDyldFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
+    if (rc)
+        kldrDyldFailure(rc, "load 2 failed for '%s', rc=%d", pExe->pMod->pszFilename);
+    g_cActiveLoadCalls--;
+    kldrDyldDoModuleTerminationAndGarabageCollection();
+
+    /*
+     * Invoke the executable entry point.
+     */
+    kldrDyldModStartExe(pExe);
+    kldrDyldFailure(-1, "failed to invoke main!");
+}
+
+
+/**
+ * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe().
+ * @internal
+ */
+static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                          unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr)
+{
+    int rc;
+
+    /*
+     * Try find the module among the ones that's already loaded.
+     */
+    rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
+    if (!rc)
+    {
+        switch ((*ppMod)->enmState)
+        {
+            /*
+             * Prerequisites are ok, so nothing to do really.
+             */
+            case KLDRSTATE_GOOD:
+            case KLDRSTATE_INITIALIZING:
+                return kldrDyldModDynamicLoad(*ppMod);
+
+            /*
+             * The module can't be loaded because it failed to initialize.
+             */
+            case KLDRSTATE_INITIALIZATION_FAILED:
+                return KLDR_ERR_MODULE_INIT_FAILED_ALREADY;
+
+            /*
+             * Prerequisites needs loading / reattaching and the module
+             * (may depending on fFlags) needs to be initialized.
+             */
+            case KLDRSTATE_PENDING_INITIALIZATION:
+                break;
+
+            /*
+             * Prerequisites needs to be loaded again
+             */
+            case KLDRSTATE_PENDING_TERMINATION:
+                break;
+
+            /*
+             * The module has been terminated so it need to be reloaded, have it's
+             * prereqs loaded, fixed up and initialized before we can use it again.
+             */
+            case KLDRSTATE_PENDING_GC:
+                rc = kldrDyldModReload(*ppMod);
+                if (rc)
+                    return kldrDyldCopyError(rc, pszErr, cchErr);
+                break;
+
+            /*
+             * Forget it, we don't know how to deal with re-initialization here.
+             */
+            case KLDRSTATE_TERMINATING:
+                KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING");
+                return KLDR_ERR_MODULE_TERMINATING;
+
+            /*
+             * Invalid state.
+             */
+            default:
+                KLDRDYLD_ASSERT(!"invalid state");
+                break;
+        }
+    }
+    else
+    {
+        /*
+         * We'll have to load it from file.
+         */
+        rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
+        if (rc)
+            return kldrDyldCopyError(rc, pszErr, cchErr);
+        rc = kldrDyldModMap(*ppMod);
+    }
+
+    /*
+     * Join cause with kLdrDyldLoadExe.
+     */
+    if (!rc)
+        rc = kldrDyldDoLoad2(*ppMod, pszPrefix, pszSuffix, enmSearch, fFlags);
+    else
+        kldrDyldStackCleanupOne(*ppMod, rc);
+
+    /*
+     * Copy any error or warning to the error buffer.
+     */
+    return kldrDyldCopyError(rc, pszErr, cchErr);
+}
+
+
+/**
+ * 2nd half of kLdrDyldLoad() and kLdrDyldLoadExe().
+ *
+ * @internal
+ */
+static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix,
+                           KLDRDYLDSEARCH enmSearch, unsigned fFlags)
+{
+    /*
+     * Load prerequisites.
+     */
+    KU32 i;
+    KU32 iLoad1st = kldrDyldStackNewFrame(pLoadedMod);
+    int rc = kldrDyldDoLoadPrerequisites(pLoadedMod, pszPrefix, pszSuffix, enmSearch, fFlags);
+    KU32 iLoadEnd = kldrDyldStackFrameCompleted();
+    if (rc)
+    {
+        kldrDyldModAddRef(pLoadedMod);
+        kldrDyldStackCleanupOne(pLoadedMod, rc); /* in case it didn't get pushed onto the stack. */
+        kldrDyldModDeref(pLoadedMod);
+    }
+
+    /*
+     * Apply fixups.
+     */
+    for (i = iLoad1st; !rc && i < iLoadEnd; i++)
+    {
+        PKLDRDYLDMOD pMod = g_papStackMods[i];
+        if (    pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
+            ||  pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES)
+            rc = kldrDyldModFixup(pMod);
+    }
+
+    /*
+     * Advance fixed up module onto initialization.
+     */
+    for (i = iLoad1st; !rc && i < iLoadEnd; i++)
+    {
+        PKLDRDYLDMOD pMod = g_papStackMods[i];
+        if (    pMod->enmState == KLDRSTATE_FIXED_UP
+            ||  pMod->enmState == KLDRSTATE_RELOADED_FIXED_UP)
+            pMod->enmState = KLDRSTATE_PENDING_INITIALIZATION;
+        KLDRDYLD_ASSERT(    pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION
+                        ||  pMod->enmState == KLDRSTATE_GOOD);
+    }
+
+    /*
+     * Call the initializers if we're loading in recursive mode or
+     * if we're the outermost load call.
+     */
+    if (fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
+    {
+        for (i = iLoad1st; !rc && i < iLoadEnd; i++)
+        {
+            PKLDRDYLDMOD pMod = g_papStackMods[i];
+            if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION)
+                rc = kldrDyldModCallInit(pMod);
+            else if (pMod->enmState == KLDRSTATE_INITIALIZATION_FAILED)
+                rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY;
+            else
+                KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
+        }
+#ifdef KLDRDYLD_STRICT
+        for (i = iLoad1st; !rc && i < iLoadEnd; i++)
+            KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
+#endif
+    }
+    else if (g_cActiveLoadCalls <= 1)
+    {
+        while (!rc && g_pkLdrDyldInitHead)
+        {
+            PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead;
+            g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
+            if (pMod->InitTerm.pNext)
+                pMod->InitTerm.pNext->InitTerm.pPrev = NULL;
+            else
+                g_pkLdrDyldInitTail = NULL;
+            pMod->fInitList = 0;
+            rc = kldrDyldModCallInit(pMod);
+        }
+    }
+
+    /*
+     * Complete the load by incrementing the dynamic load count of the
+     * requested module (return handle is already set).
+     */
+    if (!rc)
+    {
+        if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)
+        {
+            pLoadedMod->cDepRefs++; /* just make it stick. */
+            pLoadedMod->cRefs++;
+        }
+        else
+            rc = kldrDyldModDynamicLoad(pLoadedMod);
+    }
+
+    kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc);
+    return rc;
+}
+
+
+/**
+ * kldrDyldDoLoad() helper which will load prerequisites and
+ * build the initialization array / list.
+ *
+ * @returns 0 on success, non-zero error code on failure.
+ * @param   pMod            The module to start at.
+ * @param   pszPrefix       Prefix to use when searching.
+ * @param   pszSuffix       Suffix to use when searching.
+ * @param   enmSearch       Method to use when locating the module and any modules it may depend on.
+ * @param   fFlags          Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
+ */
+static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
+                                       KLDRDYLDSEARCH enmSearch, unsigned fFlags)
+{
+    static struct
+    {
+        /** The module. */
+        PKLDRDYLDMOD    pMod;
+        /** The number of prerequisite modules left to process.
+         * This starts at ~0U to inidicate that we need to load/check prerequisistes. */
+        unsigned        cLeft;
+    }               s_aEntries[64];
+    unsigned        cEntries;
+    int             rc = 0;
+
+    /* Prerequisites are always global and they just aren't executables. */
+    fFlags &= ~(KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE | KLDRDYLD_LOAD_FLAGS_EXECUTABLE);
+
+    /* push the first entry. */
+    s_aEntries[0].pMod = pMod;
+    s_aEntries[0].cLeft = ~0U;
+    cEntries = 1;
+
+    /*
+     * The recursion loop.
+     */
+    while (!rc && cEntries > 0)
+    {
+        const unsigned i = cEntries - 1;
+        pMod = s_aEntries[i].pMod;
+        if (s_aEntries[i].cLeft == ~0U)
+        {
+            /*
+             * Load prerequisite modules.
+             */
+            switch (pMod->enmState)
+            {
+                /*
+                 * Load immediate prerequisite modules and push the ones needing
+                 * attention onto the stack.
+                 */
+                case KLDRSTATE_MAPPED:
+                case KLDRSTATE_RELOADED:
+                case KLDRSTATE_PENDING_TERMINATION:
+                    rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags);
+                    KLDRDYLD_ASSERT(    pMod->enmState == KLDRSTATE_GOOD
+                                    ||  pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES
+                                    ||  pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
+                                    ||  rc);
+                    if (!rc)
+                        s_aEntries[i].cLeft = pMod->cPrereqs;
+                    break;
+
+                /*
+                 * Check its prerequisite modules the first time around.
+                 */
+                case KLDRSTATE_PENDING_INITIALIZATION:
+                    if (pMod->fAlreadySeen)
+                        break;
+                    pMod->fAlreadySeen = 1;
+                    s_aEntries[i].cLeft = pMod->cPrereqs;
+                    break;
+
+                /*
+                 * These are ok.
+                 */
+                case KLDRSTATE_LOADED_PREREQUISITES:
+                case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
+                case KLDRSTATE_INITIALIZING:
+                case KLDRSTATE_GOOD:
+                    s_aEntries[i].cLeft = 0;
+                    break;
+
+                /*
+                 * All other stats are invalid.
+                 */
+                default:
+                    KLDRDYLD_ASSERT(!"invalid state");
+                    break;
+            }
+        }
+        else if (s_aEntries[i].cLeft > 0)
+        {
+            /*
+             * Recurse down into the next prereq.
+             */
+            KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs);
+            if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0]))
+            {
+                s_aEntries[cEntries].cLeft = ~(KU32)0;
+                s_aEntries[cEntries].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft];
+                s_aEntries[i].cLeft--;
+                cEntries++;
+            }
+            else
+                rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY;
+        }
+        else
+        {
+            /*
+             * We're done with this module, record it for init/cleanup.
+             */
+            cEntries--;
+            if (pMod->enmState != KLDRSTATE_GOOD)
+            {
+                kldrDyldStackAddModule(pMod);
+                if  (   !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
+                     && !pMod->fInitList)
+                {
+                    pMod->fInitList = 1;
+                    pMod->InitTerm.pNext = NULL;
+                    pMod->InitTerm.pPrev = g_pkLdrDyldInitTail;
+                    if (g_pkLdrDyldInitTail)
+                        g_pkLdrDyldInitTail->InitTerm.pNext = pMod;
+                    else
+                        g_pkLdrDyldInitHead = pMod;
+                    g_pkLdrDyldInitTail = pMod;
+                }
+            }
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ * Gets prerequisite module.
+ *
+ * This will try load the requested module if necessary, returning it in the MAPPED state.
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure.
+ * @param   pszDll          The name of the dll to look for.
+ * @param   pszPrefix    Prefix than can be used when searching.
+ * @param   pszSuffix    Suffix than can be used when searching.
+ * @param   enmSearch       Method to use when locating the module.
+ * @param   fFlags          Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
+ * @param   pDep            The depentant module.
+ * @param   ppMod           Where to put the module we get.
+ */
+int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                            unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod)
+{
+    int             rc;
+    PKLDRDYLDMOD    pMod;
+
+    *ppMod = NULL;
+
+    /*
+     * Try find the module among the ones that's already loaded.
+     *
+     * This is very similar to the kldrDyldDoLoad code, except it has to deal with
+     * a couple of additional states and occurs only during prerequisite loading
+     * and the action taken is a little bit different.
+     */
+    rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
+    if (!rc)
+    {
+        switch (pMod->enmState)
+        {
+            /*
+             * These are good.
+             */
+            case KLDRSTATE_MAPPED:
+            case KLDRSTATE_RELOADED:
+            case KLDRSTATE_LOADED_PREREQUISITES:
+            case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
+            case KLDRSTATE_PENDING_INITIALIZATION:
+            case KLDRSTATE_INITIALIZING:
+            case KLDRSTATE_GOOD:
+            case KLDRSTATE_PENDING_TERMINATION:
+                break;
+
+            /*
+             * The module has been terminated so it need to be reloaded, have it's
+             * prereqs loaded, fixed up and initialized before we can use it again.
+             */
+            case KLDRSTATE_PENDING_GC:
+                rc = kldrDyldModReload(pMod);
+                break;
+
+            /*
+             * The module can't be loaded because it failed to initialize already.
+             */
+            case KLDRSTATE_INITIALIZATION_FAILED:
+                rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED;
+                break;
+
+            /*
+             * Forget it, no idea how to deal with re-initialization.
+             */
+            case KLDRSTATE_TERMINATING:
+                return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING;
+
+            /*
+             * Invalid state.
+             */
+            default:
+                KLDRDYLD_ASSERT(!"invalid state");
+                break;
+        }
+    }
+    else
+    {
+        /*
+         * We'll have to load it from file.
+         */
+        rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod);
+        if (!rc)
+            rc = kldrDyldModMap(pMod);
+    }
+
+    /*
+     * On success add dependency.
+     */
+    if (!rc)
+    {
+        kldrDyldModAddDep(pMod, pDep);
+        *ppMod = pMod;
+    }
+    return rc;
+}
+
+
+/**
+ * Starts a new load stack frame.
+ *
+ * @returns Where the new stack frame starts.
+ * @param   pLoadMod        The module being loaded (only used for asserting).
+ */
+static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod)
+{
+    /*
+     * Clear the fAlreadySeen flags.
+     */
+    PKLDRDYLDMOD pMod = kLdrDyldHead;
+    while (pMod)
+    {
+        pMod->fAlreadySeen = 0;
+
+#ifdef KLDRDYLD_ASSERT
+        switch (pMod->enmState)
+        {
+            case KLDRSTATE_MAPPED:
+            case KLDRSTATE_RELOADED:
+                /* only the just loaded module can be in this state. */
+                KLDRDYLD_ASSERT(pMod == pLoadMod);
+                break;
+
+            case KLDRSTATE_PENDING_INITIALIZATION:
+            case KLDRSTATE_INITIALIZING:
+            case KLDRSTATE_PENDING_TERMINATION:
+            case KLDRSTATE_PENDING_GC:
+            case KLDRSTATE_TERMINATING:
+            case KLDRSTATE_INITIALIZATION_FAILED:
+            case KLDRSTATE_PENDING_DESTROY:
+                /* requires recursion. */
+                KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1);
+                break;
+
+            case KLDRSTATE_GOOD:
+                /* requires nothing. */
+                break;
+
+            default:
+                KLDRDYLD_ASSERT(!"Invalid state");
+                break;
+        }
+#endif
+
+        /* next */
+        pMod = pMod->Load.pNext;
+    }
+    return g_cStackMods;
+}
+
+
+/**
+ * Records the module.
+ *
+ * @return 0 on success, KERR_NO_MEMORY if we can't expand the table.
+ * @param   pMod        The module to record.
+ */
+static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod)
+{
+    /*
+     * Grow the stack if necessary.
+     */
+    if (g_cStackMods + 1 > g_cStackModsAllocated)
+    {
+        KU32 cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
+        void *pvOld = g_papStackMods;
+        void *pvNew = kHlpAlloc(cNew * sizeof(g_papStackMods[0]));
+        if (!pvNew)
+            return KERR_NO_MEMORY;
+        kHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
+        g_papStackMods = (PPKLDRDYLDMOD)pvNew;
+        kHlpFree(pvOld);
+    }
+
+    /*
+     * Add a reference and push the module onto the stack.
+     */
+    kldrDyldModAddRef(pMod);
+    g_papStackMods[g_cStackMods++] = pMod;
+    return 0;
+}
+
+
+/**
+ * The frame has been completed.
+ *
+ * @returns Where the frame ends.
+ */
+static int kldrDyldStackFrameCompleted(void)
+{
+    return g_cStackMods;
+}
+
+
+/**
+ * Worker routine for kldrDyldStackDropFrame() and kldrDyldDoLoad().
+ *
+ * @param   pMod            The module to perform cleanups on.
+ * @param   rc              Used for state verification.
+ */
+static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc)
+{
+    switch (pMod->enmState)
+    {
+        /*
+         * Just push it along to the PENDING_DESTROY state.
+         */
+        case KLDRSTATE_MAPPED:
+            KLDRDYLD_ASSERT(rc);
+            kldrDyldModUnmap(pMod);
+            KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
+            break;
+
+        /*
+         * Move back to PENDING_GC.
+         */
+        case KLDRSTATE_RELOADED:
+            KLDRDYLD_ASSERT(rc);
+            pMod->enmState = KLDRSTATE_PENDING_GC;
+            break;
+
+        /*
+         * Unload prerequisites and unmap the modules.
+         */
+        case KLDRSTATE_LOADED_PREREQUISITES:
+        case KLDRSTATE_FIXED_UP:
+            KLDRDYLD_ASSERT(rc);
+            kldrDyldModUnloadPrerequisites(pMod);
+            KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
+            kldrDyldModUnmap(pMod);
+            KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
+            break;
+
+        /*
+         * Unload prerequisites and push it back to PENDING_GC.
+         */
+        case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
+        case KLDRSTATE_RELOADED_FIXED_UP:
+            kldrDyldModUnloadPrerequisites(pMod);
+            KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC);
+            break;
+
+        /*
+         * Nothing to do, just asserting sanity.
+         */
+        case KLDRSTATE_INITIALIZING:
+            /* Implies there is another load going on. */
+            KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1);
+            break;
+        case KLDRSTATE_TERMINATING:
+            /* GC in progress. */
+            KLDRDYLD_ASSERT(g_fActiveGC);
+            break;
+        case KLDRSTATE_PENDING_TERMINATION:
+        case KLDRSTATE_PENDING_INITIALIZATION:
+        case KLDRSTATE_PENDING_GC:
+        case KLDRSTATE_PENDING_DESTROY:
+            KLDRDYLD_ASSERT(rc);
+            break;
+        case KLDRSTATE_GOOD:
+            break;
+
+        /*
+         * Bad states.
+         */
+        default:
+            KLDRDYLD_ASSERT(!"drop frame bad state (a)");
+            break;
+    }
+}
+
+
+/**
+ * Done with the stack frame, dereference all the modules in it.
+ *
+ * @param   iLoad1st        The start of the stack frame.
+ * @param   iLoadEnd        The end of the stack frame.
+ * @param   rc              Used for state verification.
+ */
+static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc)
+{
+    KU32 i;
+    KLDRDYLD_ASSERT(iLoad1st <= g_cStackMods);
+    KLDRDYLD_ASSERT(iLoadEnd == g_cStackMods);
+
+    /*
+     * First pass: Do all the cleanups we can, but don't destroy anything just yet.
+     */
+    i = iLoadEnd;
+    while (i-- > iLoad1st)
+    {
+        PKLDRDYLDMOD pMod = g_papStackMods[i];
+        kldrDyldStackCleanupOne(pMod, rc);
+    }
+
+    /*
+     * Second pass: Release the references so modules pending destruction
+     *              can be completely removed.
+     */
+    for (i = iLoad1st; i < iLoadEnd ; i++)
+    {
+        PKLDRDYLDMOD pMod = g_papStackMods[i];
+
+        /*
+         * Revalidate the module state.
+         */
+        switch (pMod->enmState)
+        {
+            case KLDRSTATE_INITIALIZING:
+            case KLDRSTATE_TERMINATING:
+            case KLDRSTATE_PENDING_TERMINATION:
+            case KLDRSTATE_PENDING_INITIALIZATION:
+            case KLDRSTATE_PENDING_GC:
+            case KLDRSTATE_PENDING_DESTROY:
+            case KLDRSTATE_GOOD:
+                break;
+            default:
+                KLDRDYLD_ASSERT(!"drop frame bad state (b)");
+                break;
+        }
+
+        /*
+         * Release it.
+         */
+        kldrDyldModDeref(pMod);
+    }
+
+    /*
+     * Drop the stack frame.
+     */
+    g_cStackMods = iLoad1st;
+}
+
+
+/**
+ * Do garbage collection.
+ *
+ * This isn't doing anything unless it's called from the last
+ * load or unload call.
+ */
+static void kldrDyldDoModuleTerminationAndGarabageCollection(void)
+{
+    PKLDRDYLDMOD pMod;
+
+    /*
+     * We don't do anything until we're got rid of all recursive calls.
+     * This will ensure that we get the most optimal termination order and
+     * that we don't unload anything too early.
+     */
+    if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC)
+        return;
+    g_fActiveGC = 1;
+
+    do
+    {
+        /*
+         * 1. Release prerequisites for any left over modules.
+         */
+        for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
+        {
+            kldrDyldModAddRef(pMod);
+
+            switch (pMod->enmState)
+            {
+                case KLDRSTATE_GOOD:
+                case KLDRSTATE_PENDING_GC:
+                case KLDRSTATE_PENDING_TERMINATION:
+                    break;
+
+                case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */
+                case KLDRSTATE_PENDING_INITIALIZATION:
+                    kldrDyldModUnloadPrerequisites(pMod);
+                    break;
+
+                default:
+                    KLDRDYLD_ASSERT(!"invalid GC state (a)");
+                    break;
+            }
+
+            kldrDyldModDeref(pMod);
+        }
+
+        /*
+         * 2. Do init calls until we encounter somebody calling load/unload.
+         */
+        for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext)
+        {
+            int fRestart = 0;
+            kldrDyldModAddRef(pMod);
+
+            switch (pMod->enmState)
+            {
+                case KLDRSTATE_GOOD:
+                case KLDRSTATE_PENDING_GC:
+                    break;
+
+                case KLDRSTATE_PENDING_TERMINATION:
+                {
+                    const KU32 cTotalLoadCalls = g_cTotalLoadCalls;
+                    const KU32 cTotalUnloadCalls = g_cTotalUnloadCalls;
+                    kldrDyldModCallTerm(pMod);
+                    fRestart = cTotalLoadCalls != g_cTotalLoadCalls
+                            || cTotalUnloadCalls != g_cTotalUnloadCalls;
+                    break;
+                }
+
+                default:
+                    KLDRDYLD_ASSERT(!"invalid GC state (b)");
+                    break;
+            }
+
+            kldrDyldModDeref(pMod);
+            if (fRestart)
+                break;
+        }
+    } while (pMod);
+
+    /*
+     * Unmap and destroy modules pending for GC.
+     */
+    pMod = kLdrDyldHead;
+    while (pMod)
+    {
+        PKLDRDYLDMOD pNext = pMod->Load.pNext;
+        kldrDyldModAddRef(pMod);
+
+        switch (pMod->enmState)
+        {
+            case KLDRSTATE_INITIALIZATION_FAILED:
+            case KLDRSTATE_PENDING_GC:
+                KLDRDYLD_ASSERT(!pMod->cDepRefs);
+                KLDRDYLD_ASSERT(!pMod->cDynRefs);
+                pMod->enmState = KLDRSTATE_GC;
+                kldrDyldModUnmap(pMod);
+                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
+                kldrDyldModDestroy(pMod);
+                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED);
+                break;
+
+            case KLDRSTATE_GOOD:
+                break;
+            default:
+                KLDRDYLD_ASSERT(!"invalid GC state (c)");
+                break;
+        }
+
+        kldrDyldModDeref(pMod);
+
+        /* next */
+        pMod = pNext;
+    }
+
+    g_fActiveGC = 0;
+}
+
+
+/**
+ * Worker for kLdrDyldUnload().
+ * @internal
+ */
+static int kldrDyldDoUnload(PKLDRDYLDMOD pMod)
+{
+    return kldrDyldModDynamicUnload(pMod);
+}
+
+
+/**
+ * Worker for kLdrDyldFindByName().
+ * @internal
+ */
+static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                                unsigned fFlags, PPKLDRDYLDMOD ppMod)
+{
+    return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod);
+}
+
+
+/**
+ * Worker for kLdrDyldFindByAddress().
+ * @internal
+ */
+static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment)
+{
+    /* Scan the segments of each module in the load list. */
+    PKLDRDYLDMOD pMod = kLdrDyldHead;
+    while (pMod)
+    {
+        KU32 iSeg;
+        for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++)
+        {
+            KLDRADDR off = (KLDRADDR)Address - pMod->pMod->aSegments[iSeg].MapAddress;
+            if (off < pMod->pMod->aSegments[iSeg].cb)
+            {
+                *ppMod = pMod->hMod;
+                if (piSegment)
+                    *piSegment = iSeg;
+                if (poffSegment)
+                    *poffSegment = (KUPTR)off;
+                return 0;
+            }
+        }
+
+        /* next */
+        pMod = pMod->Load.pNext;
+    }
+
+    return KLDR_ERR_MODULE_NOT_FOUND;
+}
+
+
+/**
+ * Worker for kLdrDyldGetName().
+ * @internal
+ */
+static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName)
+{
+    return kldrDyldModGetName(pMod, pszName, cchName);
+}
+
+
+/**
+ * Worker for kLdrDyldGetFilename().
+ * @internal
+ */
+static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename)
+{
+    return kldrDyldModGetFilename(pMod, pszFilename, cchFilename);
+}
+
+
+/**
+ * Worker for kLdrDyldQuerySymbol().
+ * @internal
+ */
+static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind)
+{
+    return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind);
+}
+
+
+/**
+ * Panic / failure
+ *
+ * @returns rc if we're in a position where we can return.
+ * @param   rc              Return code.
+ * @param   pszFormat       Message string. Limited fprintf like formatted.
+ * @param   ...             Message string arguments.
+ */
+int kldrDyldFailure(int rc, const char *pszFilename, ...)
+{
+    /** @todo print it. */
+    if (g_fBootstrapping);
+        kHlpExit(1);
+    return rc;
+}
+
+
+/**
+ * Copies the error string to the user buffer.
+ *
+ * @returns rc.
+ * @param   rc      The status code.
+ * @param   pszErr  Where to copy the error string to.
+ * @param   cchErr  The size of the destination buffer.
+ */
+static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr)
+{
+    KSIZE  cchToCopy;
+
+    /* if no error string, format the rc into a string. */
+    if (!g_szkLdrDyldError[0] && rc)
+        kHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10);
+
+    /* copy it if we got something. */
+    if (cchErr && pszErr && g_szkLdrDyldError[0])
+    {
+        cchToCopy = kHlpStrLen(g_szkLdrDyldError);
+        if (cchToCopy >= cchErr)
+            cchToCopy = cchErr - 1;
+        kHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy);
+        pszErr[cchToCopy] = '\0';
+    }
+
+    return rc;
+}
+
Index: /trunk/kLdr/kLdrDyldFind.c
===================================================================
--- /trunk/kLdr/kLdrDyldFind.c	(revision 2)
+++ /trunk/kLdr/kLdrDyldFind.c	(revision 2)
@@ -0,0 +1,1088 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader, File Searching Methods.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+#if K_OS == K_OS_LINUX
+# include <k/kHlpSys.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+# ifndef LIBPATHSTRICT
+#  define LIBPATHSTRICT 3
+# endif
+  extern APIRET APIENTRY DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction);
+# define QHINF_EXEINFO       1 /* NE exeinfo. */
+# define QHINF_READRSRCTBL   2 /* Reads from the resource table. */
+# define QHINF_READFILE      3 /* Reads from the executable file. */
+# define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */
+# define QHINF_LIBPATH       5 /* Gets the entire libpath. */
+# define QHINF_FIXENTRY      6 /* NE only */
+# define QHINF_STE           7 /* NE only */
+# define QHINF_MAPSEL        8 /* NE only */
+
+#elif K_OS == K_OS_WINDOWS
+# undef IMAGE_DOS_SIGNATURE
+# undef IMAGE_NT_SIGNATURE
+# include <Windows.h>
+
+#endif
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRDYLDFIND_STRICT
+ * Define KLDRDYLDFIND_STRICT to enabled strict checks in kLdrDyldFind. */
+#define KLDRDYLDFIND_STRICT 1
+
+/** @def KLDRDYLDFIND_ASSERT
+ * Assert that an expression is true when KLDRDYLDFIND_STRICT is defined.
+ */
+#ifdef KLDRDYLDFIND_STRICT
+# define KLDRDYLDFIND_ASSERT(expr)  kHlpAssert(expr)
+#else
+# define KLDRDYLDFIND_ASSERT(expr)  do {} while (0)
+#endif
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Search arguments.
+ * This avoids a bunch of unnecessary string lengths and calculations.
+ */
+typedef struct KLDRDYLDFINDARGS
+{
+    const char *pszName;
+    KSIZE       cchName;
+
+    const char *pszPrefix;
+    KSIZE       cchPrefix;
+
+    const char *pszSuffix;
+    KSIZE       cchSuffix;
+
+    KSIZE       cchMaxLength;
+
+    KLDRDYLDSEARCH  enmSearch;
+    KU32            fFlags;
+    PPKRDR          ppRdr;
+} KLDRDYLDFINDARGS, *PKLDRDYLDFINDARGS;
+
+typedef const KLDRDYLDFINDARGS *PCKLDRDYLDFINDARGS;
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** @name The kLdr search method parameters.
+ * @{ */
+/** The kLdr EXE search path.
+ * During EXE searching the it's initialized with the values of the KLDR_PATH and
+ * the PATH env.vars. Both ';' and ':' can be used as separators.
+ */
+char            kLdrDyldExePath[8192];
+/** The kLdr DLL search path.
+ * During initialization the KLDR_LIBRARY_PATH env.var. and the path in the
+ * executable stub is appended. Both ';' and ':' can be used as separators.
+ */
+char            kLdrDyldLibraryPath[8192];
+/** The kLdr application directory.
+ * This is initialized when the executable is 'loaded' or by a kLdr user.
+ */
+char            kLdrDyldAppDir[260];
+/** The default kLdr DLL prefix.
+ * This is initialized with the KLDR_DEF_PREFIX env.var. + the prefix in the executable stub.
+ */
+char            kLdrDyldDefPrefix[16];
+/** The default kLdr DLL suffix.
+ * This is initialized with the KLDR_DEF_SUFFIX env.var. + the prefix in the executable stub.
+ */
+char            kLdrDyldDefSuffix[16];
+/** @} */
+
+
+/** @name The OS/2 search method parameters.
+ * @{
+ */
+/** The OS/2 LIBPATH.
+ * This is queried from the os2krnl on OS/2, while on other systems initialized using
+ * the KLDR_OS2_LIBPATH env.var.
+ */
+char            kLdrDyldOS2Libpath[2048];
+/** The OS/2 LIBPATHSTRICT ("T" or '\0').
+ * This is queried from the os2krnl on OS/2, while on other systems initialized using
+ * the KLDR_OS2_LIBPATHSTRICT env.var.
+ */
+char            kLdrDyldOS2LibpathStrict[8];
+/** The OS/2 BEGINLIBPATH.
+ * This is queried from the os2krnl on OS/2, while on other systems initialized using
+ * the KLDR_OS2_BEGINLIBPATH env.var.
+ */
+char            kLdrDyldOS2BeginLibpath[2048];
+/** The OS/2 ENDLIBPATH.
+ * This is queried from the os2krnl on OS/2, while on other systems initialized using
+ * the KLDR_OS2_ENDLIBPATH env.var.
+ */
+char            kLdrDyldOS2EndLibpath[2048];
+/** @} */
+
+
+/** @name The Windows search method parameters.
+ * @{ */
+/** The Windows application directory.
+ * This is initialized when the executable is 'loaded' or by a kLdr user.
+ */
+char            kLdrDyldWindowsAppDir[260];
+/** The Windows system directory.
+ * This is queried from the Win32/64 subsystem on Windows, while on other systems
+ * initialized using the KLDR_WINDOWS_SYSTEM_DIR env.var.
+ */
+char            kLdrDyldWindowsSystemDir[260];
+/** The Windows directory.
+ * This is queried from the Win32/64 subsystem on Windows, while on other systems
+ * initialized using the KLDR_WINDOWS_DIR env.var.
+ */
+char            kLdrDyldWindowsDir[260];
+/** The Windows path.
+ * This is queried from the PATH env.var. on Windows, while on other systems
+ * initialized using the KLDR_WINDOWS_PATH env.var. and falling back on
+ * the PATH env.var. if it wasn't found.
+ */
+char            kLdrDyldWindowsPath[8192];
+/** @} */
+
+
+/** @name The Common Unix search method parameters.
+ * @{
+ */
+/** The Common Unix library path.
+ * Initialized from the env.var. KLDR_UNIX_LIBRARY_PATH or LD_LIBRARY_PATH or the
+ * former wasn't found.
+ */
+char            kLdrDyldUnixLibraryPath[8192];
+/** The Common Unix system library path. */
+char            kLdrDyldUnixSystemLibraryPath[1024] = "/lib;/usr/lib";
+/** @} */
+
+/** @todo Deal with DT_RUNPATH and DT_RPATH. */
+/** @todo ld.so.cache? */
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
+                                KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr);
+static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
+                                   KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr);
+static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr);
+static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs);
+static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs);
+static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **pszPrefix,
+                                   const char **pszSuffix, const char *pszName, KU32 fFlags);
+
+
+/**
+ * Initializes the find paths.
+ *
+ * @returns 0 on success, non-zero on failure.
+ */
+int kldrDyldFindInit(void)
+{
+    KSIZE   cch;
+    int     rc;
+    char    szTmp[sizeof(kLdrDyldDefSuffix)];
+
+    /*
+     * The kLdr search parameters.
+     */
+    rc = kHlpGetEnv("KLDR_LIBRARY_PATH", kLdrDyldLibraryPath, sizeof(kLdrDyldLibraryPath));
+    rc = kHlpGetEnv("KLDR_DEF_PREFIX", szTmp, sizeof(szTmp));
+    if (!rc)
+        kHlpMemCopy(kLdrDyldDefPrefix, szTmp, sizeof(szTmp));
+    rc = kHlpGetEnv("KLDR_DEF_SUFFIX", szTmp, sizeof(szTmp));
+    if (!rc)
+        kHlpMemCopy(kLdrDyldDefSuffix, szTmp, sizeof(szTmp));
+
+    /*
+     * The OS/2 search parameters.
+     */
+#if K_OS == K_OS_OS2
+    rc = DosQueryHeaderInfo(NULLHANDLE, 0, kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath), QHINF_LIBPATH);
+    if (rc)
+        return rc;
+    rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2LibpathStrict, LIBPATHSTRICT);
+    if (rc)
+        kLdrDyldOS2LibpathStrict[0] = '\0';
+    rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2BeginLibpath, BEGIN_LIBPATH);
+    if (rc)
+        kLdrDyldOS2BeginLibpath[0] = '\0';
+    rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2EndLibpath, END_LIBPATH);
+    if (rc)
+        kLdrDyldOS2EndLibpath[0] = '\0';
+
+#else
+    kHlpGetEnv("KLDR_OS2_LIBPATH", kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath));
+    kHlpGetEnv("KLDR_OS2_LIBPATHSTRICT", kLdrDyldOS2LibpathStrict, sizeof(kLdrDyldOS2LibpathStrict));
+    if (    kLdrDyldOS2LibpathStrict[0] == 'T'
+        ||  kLdrDyldOS2LibpathStrict[0] == 't')
+        kLdrDyldOS2LibpathStrict[0] = 'T';
+    else
+        kLdrDyldOS2LibpathStrict[0] = '\0';
+    kLdrDyldOS2LibpathStrict[1] = '\0';
+    kHlpGetEnv("KLDR_OS2_BEGINLIBPATH", kLdrDyldOS2BeginLibpath, sizeof(kLdrDyldOS2BeginLibpath));
+    kHlpGetEnv("KLDR_OS2_ENDLIBPATH", kLdrDyldOS2EndLibpath, sizeof(kLdrDyldOS2EndLibpath));
+#endif
+
+    /*
+     * The windows search parameters.
+     */
+#if K_OS == K_OS_WINDOWS
+    cch = GetSystemDirectory(kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir));
+    if (cch >= sizeof(kLdrDyldWindowsSystemDir))
+        return (rc = GetLastError()) ? rc : -1;
+    cch = GetWindowsDirectory(kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir));
+    if (cch >= sizeof(kLdrDyldWindowsDir))
+        return (rc = GetLastError()) ? rc : -1;
+    kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
+#else
+    kHlpGetEnv("KLDR_WINDOWS_SYSTEM_DIR", kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir));
+    kHlpGetEnv("KLDR_WINDOWS_DIR", kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir));
+    rc = kHlpGetEnv("KLDR_WINDOWS_PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
+    if (rc)
+        kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
+#endif
+
+    /*
+     * The Unix search parameters.
+     */
+    rc = kHlpGetEnv("KLDR_UNIX_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath));
+    if (rc)
+        kHlpGetEnv("LD_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath));
+
+    (void)cch;
+    return 0;
+}
+
+
+/**
+ * Lazily initialize the two application directory paths.
+ */
+static void kldrDyldFindLazyInitAppDir(void)
+{
+    if (!kLdrDyldAppDir[0])
+    {
+#if K_OS == K_OS_DARWIN
+        /** @todo implement this! */
+        kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
+        kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
+
+#elif K_OS == K_OS_LINUX
+        KSSIZE cch = kHlpSys_readlink("/proc/self/exe", kLdrDyldAppDir, sizeof(kLdrDyldAppDir) - 1);
+        if (cch > 0)
+        {
+            kLdrDyldAppDir[cch] = '\0';
+            *kHlpGetFilename(kLdrDyldAppDir) = '\0';
+            kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
+        }
+        else
+        {
+            kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
+            kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
+        }
+
+#elif K_OS == K_OS_OS2
+        PPIB pPib;
+        PTIB pTib;
+        APIRET rc;
+
+        DosGetInfoBlocks(&pTib, &pPib);
+        rc = DosQueryModuleName(pPib->pib_hmte, sizeof(kLdrDyldAppDir), kLdrDyldAppDir);
+        if (!rc)
+        {
+            *kHlpGetFilename(kLdrDyldAppDir) = '\0';
+             kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
+        }
+        else
+        {
+            kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
+            kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
+        }
+
+#elif K_OS == K_OS_WINDOWS
+        DWORD dwSize = GetModuleFileName(NULL /* the executable */, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
+        if (dwSize > 0)
+        {
+            *kHlpGetFilename(kLdrDyldAppDir) = '\0';
+            kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
+        }
+        else
+        {
+            kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
+            kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
+        }
+
+#else
+# error "Port me"
+#endif
+    }
+}
+
+
+/**
+ * Locates and opens a module using the specified search method.
+ *
+ * @returns 0 and *ppMod on success, non-zero OS specific error on failure.
+ *
+ * @param   pszName         Partial or complete name, it's specific to the search method to determin which.
+ * @param   pszPrefix       Prefix than can be used when searching.
+ * @param   pszSuffix       Suffix than can be used when searching.
+ * @param   enmSearch       The file search method to apply.
+ * @param   fFlags          Search flags.
+ * @param   ppMod           Where to store the file provider instance on success.
+ */
+int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
+                          KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod)
+{
+    int rc;
+    PKRDR pRdr = NULL;
+
+    *ppMod = NULL;
+
+    /*
+     * If this isn't just a filename, we the caller has specified a file
+     * that should be opened directly and not a module name to be searched for.
+     */
+    if (!kHlpIsFilenameOnly(pszName))
+        rc = kldrDyldFindTryOpen(pszName, &pRdr);
+    else if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
+        rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
+    else
+        rc = kldrDyldFindDoExeSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
+    if (!rc)
+    {
+#ifdef KLDRDYLDFIND_STRICT
+        /* Sanity check of kldrDyldFindExistingModule. */
+        if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)
+        {
+            const char     *pszFilename = kRdrName(pRdr);
+            const KSIZE     cchFilename = kHlpStrLen(pszFilename);
+            PKLDRDYLDMOD    pCur;
+            for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
+                KLDRDYLDFIND_ASSERT(    pCur->pMod->cchFilename != cchFilename
+                                    ||  kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename));
+        }
+#endif
+
+        /*
+         * Check for matching non-global modules that should be promoted.
+         */
+        if (!(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
+        {
+            const char     *pszFilename = kRdrName(pRdr);
+            const KSIZE     cchFilename = kHlpStrLen(pszFilename);
+            PKLDRDYLDMOD    pCur;
+            for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
+            {
+                if (    !pCur->fGlobalOrSpecific
+                    &&  pCur->pMod->cchFilename == cchFilename
+                    &&  !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename))
+                {
+                    kRdrClose(pRdr);
+                    kldrDyldModMarkGlobal(pCur);
+                    *ppMod = pCur;
+                    return 0;
+                }
+                KLDRDYLDFIND_ASSERT(    pCur->pMod->cchFilename != cchFilename
+                                    ||  kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename));
+            }
+        }
+
+        /*
+         * Create a new module.
+         */
+        rc = kldrDyldModCreate(pRdr, fFlags, ppMod);
+        if (rc)
+            kRdrClose(pRdr);
+    }
+    return rc;
+}
+
+
+/**
+ * Searches for a DLL file using the specified method.
+ *
+ * @returns 0 on success and *ppMod pointing to the new module.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
+ * @returns non-zero kLdr or OS specific status code on other failures.
+ * @param   pszName     The name.
+ * @param   pszPrefix   The prefix, optional.
+ * @param   pszSuffix   The suffix, optional.
+ * @param   enmSearch   The search method.
+ * @param   fFlags      The load/search flags.
+ * @param   ppRdr       Where to store the pointer to the file provider instance on success.
+ */
+static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
+                                   KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr)
+{
+    int rc;
+    KLDRDYLDFINDARGS Args;
+
+    /*
+     * Initialize the argument structure and resolve defaults.
+     */
+    Args.enmSearch = enmSearch;
+    Args.pszPrefix = pszPrefix;
+    Args.pszSuffix = pszSuffix;
+    rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags);
+    if (rc)
+        return rc;
+    Args.pszName = pszName;
+    Args.cchName = kHlpStrLen(pszName);
+    Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0;
+    Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0;
+    Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix;
+    Args.fFlags = fFlags;
+    Args.ppRdr = ppRdr;
+
+    /*
+     * Apply the specified search method.
+     */
+/** @todo get rid of the strlen() on the various paths here! */
+    switch (Args.enmSearch)
+    {
+        case KLDRDYLD_SEARCH_KLDR:
+        {
+            kldrDyldFindLazyInitAppDir();
+            if (kLdrDyldAppDir[0] != '\0')
+            {
+                rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args);
+                if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                    break;
+            }
+            rc = kldrDyldFindTryOpenPath(".", 1, &Args);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                break;
+            rc = kldrDyldFindEnumeratePath(kLdrDyldLibraryPath, &Args);
+            break;
+        }
+
+        case KLDRDYLD_SEARCH_OS2:
+        {
+            rc = kldrDyldFindEnumeratePath(kLdrDyldOS2BeginLibpath, &Args);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                break;
+            rc = kldrDyldFindEnumeratePath(kLdrDyldOS2Libpath, &Args);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                break;
+            rc = kldrDyldFindEnumeratePath(kLdrDyldOS2EndLibpath, &Args);
+            break;
+        }
+
+        case KLDRDYLD_SEARCH_WINDOWS:
+        case KLDRDYLD_SEARCH_WINDOWS_ALTERED:
+        {
+            kldrDyldFindLazyInitAppDir();
+            rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsAppDir, kHlpStrLen(kLdrDyldWindowsAppDir), &Args);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                break;
+            if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED)
+            {
+                rc = kldrDyldFindTryOpenPath(".", 1, &Args);
+                if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                    break;
+            }
+            rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsSystemDir, kHlpStrLen(kLdrDyldWindowsSystemDir), &Args);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                break;
+            rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsDir, kHlpStrLen(kLdrDyldWindowsDir), &Args);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                break;
+            if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS)
+            {
+                rc = kldrDyldFindTryOpenPath(".", 1, &Args);
+                if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                    break;
+            }
+            rc = kldrDyldFindEnumeratePath(kLdrDyldWindowsPath, &Args);
+            break;
+        }
+
+        case KLDRDYLD_SEARCH_UNIX_COMMON:
+        {
+            rc = kldrDyldFindEnumeratePath(kLdrDyldUnixLibraryPath, &Args);
+            if (rc == KLDR_ERR_MODULE_NOT_FOUND)
+                break;
+            rc = kldrDyldFindEnumeratePath(kLdrDyldUnixSystemLibraryPath, &Args);
+            break;
+        }
+
+        default: kHlpAssert(!"internal error"); return -1;
+    }
+    return rc;
+}
+
+
+/**
+ * Searches for an EXE file using the specified method.
+ *
+ * @returns 0 on success and *ppMod pointing to the new module.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
+ * @returns non-zero kLdr or OS specific status code on other failures.
+ * @param   pszName     The name.
+ * @param   pszPrefix   The prefix, optional.
+ * @param   pszSuffix   The suffix, optional.
+ * @param   enmSearch   The search method.
+ * @param   fFlags      The load/search flags.
+ * @param   ppRdr       Where to store the pointer to the file provider instance on success.
+ */
+static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
+                                   KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr)
+{
+    int rc;
+    KLDRDYLDFINDARGS Args;
+
+    /*
+     * Initialize the argument structure and resolve defaults.
+     */
+    Args.enmSearch = enmSearch;
+    Args.pszPrefix = pszPrefix;
+    Args.pszSuffix = pszSuffix;
+    rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags);
+    if (rc)
+        return rc;
+    Args.pszName = pszName;
+    Args.cchName = kHlpStrLen(pszName);
+    Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0;
+    Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0;
+    Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix;
+    Args.fFlags = fFlags;
+    Args.ppRdr = ppRdr;
+
+    /*
+     * If we're bootstrapping a process, we'll start by looking in the
+     * application directory and the check out the path.
+     */
+    if (g_fBootstrapping)
+    {
+        kldrDyldFindLazyInitAppDir();
+        if (kLdrDyldAppDir[0] != '\0')
+        {
+            rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                return rc;
+        }
+    }
+
+    /*
+     * Search the EXE search path. Initialize it the first time around.
+     */
+    if (!kLdrDyldExePath[0])
+    {
+        KSIZE cch;
+        kHlpGetEnv("KLDR_EXE_PATH", kLdrDyldExePath, sizeof(kLdrDyldExePath) - 10);
+        cch = kHlpStrLen(kLdrDyldExePath);
+        kLdrDyldExePath[cch++] = ';';
+        kHlpGetEnv("PATH", &kLdrDyldExePath[cch], sizeof(kLdrDyldExePath) - cch);
+    }
+    return kldrDyldFindEnumeratePath(kLdrDyldExePath, &Args);
+}
+
+
+/**
+ * Try open the specfied file.
+ *
+ * @returns 0 on success and *ppMod pointing to the new module.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
+ * @returns non-zero kLdr or OS specific status code on other failures.
+ * @param   pszFilename     The filename.
+ * @param   ppRdr           Where to store the pointer to the new module.
+ */
+static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr)
+{
+    int rc;
+
+    /*
+     * Try open the file.
+     */
+    rc = kRdrOpen(ppRdr, pszFilename);
+    if (!rc)
+        return 0;
+    /** @todo deal with return codes properly. */
+    if (rc >= KERR_BASE && rc <= KERR_END)
+        return rc;
+
+    return KLDR_ERR_MODULE_NOT_FOUND;
+}
+
+
+/**
+ * Composes a filename from the specified directory path,
+ * prefix (optional), name and suffix (optional, will try with and without).
+ *
+ * @param   pchPath     The directory path - this doesn't have to be null terminated.
+ * @param   cchPath     The length of the path.
+ * @param   pArgs       The search argument structure.
+ *
+ * @returns See kldrDyldFindTryOpen
+ */
+static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs)
+{
+    static char s_szFilename[1024];
+    char *psz;
+    int rc;
+
+    /*
+     * Ignore any attempts at opening empty paths.
+     * This can happen when a *Dir globals is empty.
+     */
+    if (!cchPath)
+        return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */
+
+    /*
+     * Limit check first.
+     */
+    if (cchPath + 1 + pArgs->cchMaxLength >= sizeof(s_szFilename))
+    {
+        KLDRDYLDFIND_ASSERT(!"too long");
+        return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */
+    }
+
+    /*
+     * The directory path.
+     */
+    kHlpMemCopy(s_szFilename, pchPath, cchPath);
+    psz = &s_szFilename[cchPath];
+    if (psz[-1] != '/'
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+        && psz[-1] != '\\'
+        && psz[-1] != ':'
+#endif
+        )
+        *psz++ = '/';
+
+    /*
+     * The name.
+     */
+    if (pArgs->cchPrefix)
+    {
+        kHlpMemCopy(psz, pArgs->pszPrefix, pArgs->cchPrefix);
+        psz += pArgs->cchPrefix;
+    }
+    kHlpMemCopy(psz, pArgs->pszName, pArgs->cchName);
+    psz += pArgs->cchName;
+    if (pArgs->cchSuffix)
+    {
+        kHlpMemCopy(psz, pArgs->pszSuffix, pArgs->cchSuffix);
+        psz += pArgs->cchSuffix;
+    }
+    *psz = '\0';
+
+
+    /*
+     * Try open it.
+     */
+    rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr);
+    /* If we're opening an executable, try again without the suffix.*/
+    if (    rc
+        &&  pArgs->cchSuffix
+        &&  (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
+    {
+        psz -= pArgs->cchSuffix;
+        *psz = '\0';
+        rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr);
+    }
+    return rc;
+}
+
+
+/**
+ * Enumerates the specfied path.
+ *
+ * @returns Any return code from the kldrDyldFindTryOpenPath() which isn't KLDR_ERR_MODULE_NOT_FOUND.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND if the end of the search path was reached.
+ * @param   pszSearchPath   The search path to enumeare.
+ * @param   pArgs       The search argument structure.
+ */
+static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs)
+{
+    const char *psz = pszSearchPath;
+    for (;;)
+    {
+        const char *pszEnd;
+        KSIZE       cchPath;
+
+        /*
+         * Trim.
+         */
+        while (*psz == ';' || *psz == ':')
+            psz++;
+        if (*psz == '\0')
+            return KLDR_ERR_MODULE_NOT_FOUND;
+
+        /*
+         * Find the end.
+         */
+        pszEnd = psz + 1;
+        while (     *pszEnd != '\0'
+               &&   *pszEnd != ';'
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+               && (     *pszEnd != ':'
+                   ||   (   pszEnd - psz == 1
+                         && (   (*psz >= 'A' && *psz <= 'Z')
+                             || (*psz >= 'a' && *psz <= 'z')
+                            )
+                        )
+                  )
+#else
+               && *pszEnd != ':'
+#endif
+              )
+            pszEnd++;
+
+        /*
+         * If not empty path, try open the module using it.
+         */
+        cchPath = pszEnd - psz;
+        if (cchPath > 0)
+        {
+            int rc;
+            rc = kldrDyldFindTryOpenPath(psz, cchPath, pArgs);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                return rc;
+        }
+
+        /* next */
+        psz = pszEnd;
+    }
+}
+
+
+/**
+ * Resolve default search method, prefix and suffix.
+ *
+ * @returns 0 on success, KERR_INVALID_PARAMETER on failure.
+ * @param   penmSearch  The search method. In/Out.
+ * @param   ppszPrefix  The prefix. In/Out.
+ * @param   ppszSuffix  The suffix. In/Out.
+ * @param   pszName     The name. In.
+ * @param   fFlags      The load/search flags.
+ */
+static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **ppszPrefix, const char **ppszSuffix,
+                                   const char *pszName, KU32 fFlags)
+{
+    unsigned fCaseSensitive;
+
+    /*
+     * Fixup search method alias.
+     */
+    if (*penmSearch == KLDRDYLD_SEARCH_HOST)
+#if K_OS == K_OS_DARWIN
+        /** @todo *penmSearch = KLDRDYLD_SEARCH_DARWIN; */
+        *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON;
+#elif K_OS == K_OS_FREEBSD \
+   || K_OS == K_OS_LINUX \
+   || K_OS == K_OS_NETBSD \
+   || K_OS == K_OS_OPENBSD \
+   || K_OS == K_OS_SOLARIS
+        *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON;
+#elif K_OS == K_OS_OS2
+        *penmSearch = KLDRDYLD_SEARCH_OS2;
+#elif K_OS == K_OS_WINDOWS
+        *penmSearch = KLDRDYLD_SEARCH_WINDOWS;
+#else
+# error "Port me"
+#endif
+
+    /*
+     * Apply search method specific prefix/suffix.
+     */
+    switch (*penmSearch)
+    {
+        case KLDRDYLD_SEARCH_KLDR:
+            if (!*ppszPrefix && kLdrDyldDefPrefix[0])
+                *ppszPrefix = kLdrDyldDefPrefix;
+            if (!*ppszSuffix && kLdrDyldDefSuffix[0])
+                *ppszSuffix = kLdrDyldDefSuffix;
+            fCaseSensitive = 1;
+            break;
+
+        case KLDRDYLD_SEARCH_OS2:
+            if (!*ppszSuffix)
+                *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe";
+            fCaseSensitive = 0;
+            break;
+
+        case KLDRDYLD_SEARCH_WINDOWS:
+        case KLDRDYLD_SEARCH_WINDOWS_ALTERED:
+            if (!*ppszSuffix)
+                *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe";
+            fCaseSensitive = 0;
+            break;
+
+        case KLDRDYLD_SEARCH_UNIX_COMMON:
+            fCaseSensitive = 1;
+            break;
+
+        default:
+            KLDRDYLDFIND_ASSERT(!"invalid search method");
+            return KERR_INVALID_PARAMETER;
+    }
+
+    /*
+     * Drop the suffix if it's already included in the name.
+     */
+    if (*ppszSuffix)
+    {
+        const KSIZE cchName = kHlpStrLen(pszName);
+        const KSIZE cchSuffix = kHlpStrLen(*ppszSuffix);
+        if (    cchName > cchSuffix
+            &&  (   fCaseSensitive
+                 ?  !kHlpMemComp(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix)
+                 :  !kHlpMemICompAscii(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix))
+           )
+            *ppszSuffix = NULL;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Locates an already open module using the specified search method.
+ *
+ * @returns 0 and *ppMod on success, non-zero OS specific error on failure.
+ *
+ * @param   pszName         Partial or complete name, it's specific to the search method to determin which.
+ * @param   pszPrefix       Prefix than can be used when searching.
+ * @param   pszSuffix       Suffix than can be used when searching.
+ * @param   enmSearch       The file search method to apply.
+ * @param   fFlags          Search flags.
+ * @param   ppMod           Where to store the file provider instance on success.
+ */
+int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
+                               KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod)
+{
+
+    int rc;
+    unsigned fOS2LibpathStrict;
+    *ppMod = NULL;
+
+    /*
+     * Don't bother if no modules are loaded yet.
+     */
+    if (!kLdrDyldHead)
+        return KLDR_ERR_MODULE_NOT_FOUND;
+
+    /*
+     * Defaults.
+     */
+    rc = kldrDyldFindGetDefaults(&enmSearch, &pszPrefix, &pszSuffix, pszName, fFlags);
+    if (rc)
+        return rc;
+
+    /*
+     * If this isn't just a filename, the caller has specified a file
+     * that should be opened directly and not a module name to be searched for.
+     *
+     * In order to do the right thing we'll have to open the file and get the
+     * correct filename for it.
+     *
+     * The OS/2 libpath strict method require us to find the correct DLL first.
+     */
+    fOS2LibpathStrict = 0;
+    if (    !kHlpIsFilenameOnly(pszName)
+        ||  (fOS2LibpathStrict = (   enmSearch == KLDRDYLD_SEARCH_OS2
+                                  && kLdrDyldOS2LibpathStrict[0] == 'T')
+            )
+       )
+    {
+        PKRDR pRdr;
+        if (fOS2LibpathStrict)
+            rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
+        else
+            rc = kldrDyldFindTryOpen(pszName, &pRdr);
+        if (!rc)
+        {
+            /* do a filename based search. */
+            const char     *pszFilename = kRdrName(pRdr);
+            const KSIZE     cchFilename = kHlpStrLen(pszFilename);
+            PKLDRDYLDMOD    pCur;
+            rc = KLDR_ERR_MODULE_NOT_FOUND;
+            for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
+            {
+                if (    pCur->pMod->cchFilename == cchFilename
+                    &&  !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename))
+                {
+                    *ppMod = pCur;
+                    rc = 0;
+                    break;
+                }
+            }
+            kRdrClose(pRdr);
+        }
+    }
+    else
+    {
+        const KSIZE     cchName = kHlpStrLen(pszName);
+        const KSIZE     cchPrefix = pszPrefix ? kHlpStrLen(pszPrefix) : 0;
+        const KSIZE     cchSuffix = pszSuffix ? kHlpStrLen(pszSuffix) : 0;
+        const char     *pszNameSuffix = kHlpGetSuff(pszName);
+        PKLDRDYLDMOD    pCur = kLdrDyldHead;
+
+        /*
+         * Some of the methods are case insensitive (ASCII), others are case sensitive.
+         * To avoid having todo indirect calls to the compare functions here, we split
+         * ways even if it means a lot of duplicate code.
+         */
+        if (   enmSearch == KLDRDYLD_SEARCH_OS2
+            || enmSearch == KLDRDYLD_SEARCH_WINDOWS
+            || enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED)
+        {
+            const unsigned fNameHasSuffix = pszNameSuffix
+                                         && kHlpStrLen(pszNameSuffix) == cchSuffix
+                                         && !kHlpMemICompAscii(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix);
+            for (; pCur; pCur = pCur->Load.pNext)
+            {
+                /* match global / specific */
+                if (    !pCur->fGlobalOrSpecific
+                    &&  !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
+                    continue;
+
+                /* match name */
+                if (    pCur->pMod->cchName == cchName
+                    &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName))
+                    break;
+                if (cchPrefix)
+                {
+                    if (    pCur->pMod->cchName == cchName + cchPrefix
+                        &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
+                        &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName))
+                    break;
+                }
+                if (cchSuffix)
+                {
+                    if (    pCur->pMod->cchName == cchName + cchSuffix
+                        &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix)
+                        &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName))
+                    break;
+                    if (    fNameHasSuffix
+                        &&  pCur->pMod->cchName == cchName - cchSuffix
+                        &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName - cchSuffix))
+                    break;
+                    if (cchPrefix)
+                    {
+                        if (    pCur->pMod->cchName == cchName + cchPrefix + cchSuffix
+                            &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
+                            &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName)
+                            &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix))
+                        break;
+                        if (    fNameHasSuffix
+                            &&  pCur->pMod->cchName == cchName + cchPrefix - cchSuffix
+                            &&  !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
+                            &&  !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix))
+                        break;
+                    }
+                }
+            }
+        }
+        else
+        {
+            const unsigned fNameHasSuffix = pszNameSuffix
+                                         && kHlpStrLen(pszNameSuffix) == cchSuffix
+                                         && kHlpMemComp(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix);
+            for (; pCur; pCur = pCur->Load.pNext)
+            {
+                /* match global / specific */
+                if (    !pCur->fGlobalOrSpecific
+                    &&  !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
+                    continue;
+
+                /* match name */
+                if (    pCur->pMod->cchName == cchName
+                    &&  !kHlpMemComp(pCur->pMod->pszName, pszName, cchName))
+                    break;
+                if (cchPrefix)
+                {
+                    if (    pCur->pMod->cchName == cchName + cchPrefix
+                        &&  !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
+                        &&  !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName))
+                    break;
+                }
+                if (cchSuffix)
+                {
+                    if (    pCur->pMod->cchName == cchName + cchSuffix
+                        &&  !kHlpMemComp(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix)
+                        &&  !kHlpMemComp(pCur->pMod->pszName, pszName, cchName))
+                    break;
+                    if (    fNameHasSuffix
+                        &&  pCur->pMod->cchName == cchName - cchSuffix
+                        &&  !kHlpMemComp(pCur->pMod->pszName, pszName, cchName - cchSuffix))
+                    break;
+                    if (cchPrefix)
+                    {
+                        if (    pCur->pMod->cchName == cchName + cchPrefix + cchSuffix
+                            &&  !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
+                            &&  !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName)
+                            &&  !kHlpMemComp(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix))
+                        break;
+                        if (    pCur->pMod->cchName == cchName + cchPrefix - cchSuffix
+                            &&  !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
+                            &&  !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix))
+                        break;
+                    }
+                }
+            }
+        }
+
+        /* search result. */
+        if (pCur)
+        {
+            *ppMod = pCur;
+            rc = 0;
+        }
+        else
+            rc = KLDR_ERR_MODULE_NOT_FOUND;
+    }
+
+    return rc;
+}
+
Index: /trunk/kLdr/kLdrDyldMod.c
===================================================================
--- /trunk/kLdr/kLdrDyldMod.c	(revision 2)
+++ /trunk/kLdr/kLdrDyldMod.c	(revision 2)
@@ -0,0 +1,1301 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader, Dyld module methods.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRDYLDMOD_STRICT
+ * Define KLDRDYLDMOD_STRICT to enabled strict checks in kLdrDyld. */
+#define KLDRDYLDMOD_STRICT 1
+
+/** @def KLDRDYLDMOD_ASSERT
+ * Assert that an expression is true when KLDRDYLD_STRICT is defined.
+ */
+#ifdef KLDRDYLDMOD_STRICT
+# define KLDRDYLDMOD_ASSERT(expr)  kHlpAssert(expr)
+#else
+# define KLDRDYLDMOD_ASSERT(expr)  do {} while (0)
+#endif
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static void kldrDyldModUnlink(PKLDRDYLDMOD pMod);
+
+
+
+/**
+ * Creates a module from the specified file provider instance.
+ *
+ * @returns 0 on success and *ppMod pointing to the new instance.
+ *          On failure a non-zero kLdr status code is returned.
+ * @param   pRdr    The file provider instance.
+ * @param   fFlags  Load/search flags.
+ * @param   ppMod   Where to put the pointer to the new module on success.
+ */
+int kldrDyldModCreate(PKRDR pRdr, KU32 fFlags, PPKLDRDYLDMOD ppMod)
+{
+    PKLDRDYLDMOD pMod;
+    PKLDRMOD pRawMod;
+    int rc;
+
+    *ppMod = NULL;
+
+/** @todo deal with fFlags (exec/dll) */
+
+    /*
+     * Try open an module interpreter.
+     */
+    rc = kLdrModOpenFromRdr(pRdr, &pRawMod);
+    if (rc)
+        return kldrDyldFailure(rc, "%s: %rc", kRdrName(pRdr), rc);
+
+    /*
+     * Match the module aginst the load flags.
+     */
+    switch (pRawMod->enmType)
+    {
+        case KLDRTYPE_EXECUTABLE_FIXED:
+        case KLDRTYPE_EXECUTABLE_RELOCATABLE:
+        case KLDRTYPE_EXECUTABLE_PIC:
+            if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
+            {
+                kLdrModClose(pRawMod);
+                return KLDR_ERR_NOT_EXE;
+            }
+            break;
+
+        case KLDRTYPE_OBJECT: /* We can handle these as DLLs. */
+        case KLDRTYPE_SHARED_LIBRARY_FIXED:
+        case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE:
+        case KLDRTYPE_SHARED_LIBRARY_PIC:
+        case KLDRTYPE_FORWARDER_DLL:
+            if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)
+            {
+                kLdrModClose(pRawMod);
+                return KLDR_ERR_NOT_DLL;
+            }
+            break;
+
+        default:
+            KLDRDYLDMOD_ASSERT(!"Bad enmType!");
+        case KLDRTYPE_CORE:
+            return fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE ? KLDR_ERR_NOT_EXE : KLDR_ERR_NOT_DLL;
+    }
+
+    /*
+     * Allocate a new dyld module.
+     */
+    pMod = (PKLDRDYLDMOD)kHlpAlloc(sizeof(*pMod));
+    if (pMod)
+    {
+        pMod->enmState = KLDRSTATE_OPEN;
+        pMod->pMod = pRawMod;
+        pMod->hMod = pMod;
+        pMod->cDepRefs = pMod->cDynRefs = pMod->cRefs = 0;
+        switch (pRawMod->enmType)
+        {
+            case KLDRTYPE_EXECUTABLE_FIXED:
+            case KLDRTYPE_EXECUTABLE_RELOCATABLE:
+            case KLDRTYPE_EXECUTABLE_PIC:
+                pMod->fExecutable = 1;
+                break;
+            default:
+                pMod->fExecutable = 0;
+                break;
+        }
+        pMod->fGlobalOrSpecific = 0;
+        pMod->fBindable = 0;
+        pMod->fInitList = 0;
+        pMod->fAlreadySeen = 0;
+        pMod->fMapped = 0;
+        pMod->fAllocatedTLS = 0;
+        pMod->f25Reserved = 0;
+        pMod->InitTerm.pNext = NULL;
+        pMod->InitTerm.pPrev = NULL;
+        pMod->Bind.pNext = NULL;
+        pMod->Bind.pPrev = NULL;
+        pMod->cPrereqs = 0;
+        pMod->papPrereqs = NULL;
+        pMod->u32MagicHead = KLDRDYMOD_MAGIC;
+        pMod->u32MagicTail = KLDRDYMOD_MAGIC;
+
+        /* it. */
+        pMod->Load.pNext = NULL;
+        pMod->Load.pPrev = kLdrDyldTail;
+        if (kLdrDyldTail)
+            kLdrDyldTail->Load.pNext = pMod;
+        else
+            kLdrDyldHead = pMod;
+        kLdrDyldTail = pMod;
+
+        /* deal with the remaining flags. */
+        if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)
+            kldrDyldModMarkSpecific(pMod);
+        else
+            kldrDyldModMarkGlobal(pMod);
+
+        if (fFlags & KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS)
+            kldrDyldModSetBindable(pMod, 0 /* not deep binable */);
+        else
+            kldrDyldModClearBindable(pMod);
+
+        /*
+         * We're good.
+         */
+        *ppMod = pMod;
+        rc = 0;
+    }
+    else
+    {
+        kLdrModClose(pRawMod);
+        rc = KERR_NO_MEMORY;
+    }
+    return rc;
+}
+
+
+/**
+ * Creates a module for a native module.
+ *
+ * @returns 0 on success and *ppMod pointing to the new instance.
+ *          On failure a non-zero kLdr status code is returned.
+ * @param   hNativeModule   The native handle.
+ * @param   ppMod           Where to put the pointer to the new module on success.
+ * @remark  This function ain't finalized yet.
+ */
+int kldrDyldModCreateNative(KUPTR hNativeModule)
+{
+#if 0
+    /*
+     * Check if this module is already loaded by the native OS loader.
+     */
+    rc = kld
+    {
+#if K_OS == K_OS_OS2
+    HMODULE hmod = NULLHANDLE;
+    APIRET rc = DosQueryModuleHandle(kRdrName(pRdr), &hmod);
+    if (!rc)
+
+#elif K_OS == K_OS_WINDOWS
+    HMODULE hmod = NULL;
+    if (GetModuleHandle(kRdrName(pRdr))
+
+#else
+# error "Port me"
+#endif
+    }
+#endif
+    return -1;
+}
+
+
+/**
+ * Destroys a module pending destruction.
+ *
+ * @param   pMod        The module in question.
+ */
+void kldrDyldModDestroy(PKLDRDYLDMOD pMod)
+{
+    int rc;
+
+    /*
+     * Validate the state.
+     */
+    switch (pMod->enmState)
+    {
+        case KLDRSTATE_PENDING_DESTROY:
+        case KLDRSTATE_GC:
+            break;
+        default:
+            KLDRDYLDMOD_ASSERT(!"Invalid state");
+            break;
+    }
+    KLDRDYLDMOD_ASSERT(!pMod->fInitList);
+    KLDRDYLDMOD_ASSERT(!pMod->cDynRefs);
+    KLDRDYLDMOD_ASSERT(!pMod->cDepRefs);
+
+    /*
+     * Ensure that the module is unmapped.
+     */
+    if (pMod->fAllocatedTLS)
+    {
+        kLdrModFreeTLS(pMod->pMod);
+        pMod->fAllocatedTLS = 0;
+    }
+    if (pMod->fMapped)
+    {
+        rc = kLdrModUnmap(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc);
+        pMod->fMapped = 0;
+    }
+
+    /*
+     * Ensure it's unlinked from all chains.
+     */
+    if (pMod->enmState < KLDRSTATE_PENDING_DESTROY)
+        kldrDyldModUnlink(pMod);
+
+    /*
+     * Free everything associated with the module.
+     */
+    /* the prerequisite array. */
+    if (pMod->papPrereqs)
+    {
+        KU32 i = pMod->cPrereqs;
+        while (i-- > 0)
+        {
+            KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL);
+            pMod->papPrereqs[i] = NULL;
+        }
+
+        kHlpFree(pMod->papPrereqs);
+        pMod->papPrereqs = NULL;
+        pMod->cPrereqs = 0;
+    }
+
+    /* the module interpreter.  */
+    if (pMod->pMod)
+    {
+        rc = kLdrModClose(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc);
+        pMod->pMod = NULL;
+    }
+
+
+    /*
+     * Finally, change the module state and free the module if
+     * there are not more references to it. If somebody is still
+     * referencing it, postpone the freeing to Deref.
+     */
+    pMod->enmState = KLDRSTATE_DESTROYED;
+    if (!pMod->cRefs)
+    {
+        pMod->u32MagicHead = 1;
+        pMod->u32MagicTail = 2;
+        kHlpFree(pMod);
+    }
+}
+
+
+/**
+ * Unlinks the module from any list it might be in.
+ * It is assumed that the module is at least linked into the load list.
+ *
+ * @param   pMod    The moduel.
+ */
+static void kldrDyldModUnlink(PKLDRDYLDMOD pMod)
+{
+    /* load list */
+    if (pMod->Load.pNext)
+        pMod->Load.pNext->Load.pPrev = pMod->Load.pPrev;
+    else
+        kLdrDyldTail = pMod->Load.pPrev;
+    if (pMod->Load.pPrev)
+        pMod->Load.pPrev->Load.pNext = pMod->Load.pNext;
+    else
+        kLdrDyldHead = pMod->Load.pNext;
+
+    /* bind list */
+    if (pMod->fBindable)
+        kldrDyldModClearBindable(pMod);
+
+    /* init term */
+    if (pMod->fInitList)
+    {
+        KLDRDYLDMOD_ASSERT(pMod->enmState < KLDRSTATE_INITIALIZATION_FAILED);
+        pMod->fInitList = 0;
+        if (pMod->InitTerm.pNext)
+            pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev;
+        else
+            g_pkLdrDyldInitTail = pMod->InitTerm.pPrev;
+        if (pMod->InitTerm.pPrev)
+            pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext;
+        else
+            g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
+    }
+    else if (pMod->enmState > KLDRSTATE_INITIALIZATION_FAILED)
+    {
+        KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_GOOD);
+        if (pMod->InitTerm.pNext)
+            pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev;
+        else
+            g_pkLdrDyldTermTail = pMod->InitTerm.pPrev;
+        if (pMod->InitTerm.pPrev)
+            pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext;
+        else
+            g_pkLdrDyldTermHead = pMod->InitTerm.pNext;
+    }
+    pMod->InitTerm.pNext = NULL;
+    pMod->InitTerm.pPrev = NULL;
+}
+
+
+/**
+ * Marks a module as bindable, i.e. it'll be considered when
+ * resolving names the unix way.
+ *
+ * @param   pMod    The module.
+ * @param   fDeep   When set the module will be inserted at the head of the
+ *                  module list used to resolve symbols. This means that the
+ *                  symbols in this module will be prefered of all the other
+ *                  modules.
+ */
+void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep)
+{
+    KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_GC);
+    if (!pMod->fBindable)
+    {
+        pMod->fBindable = 1;
+        if (!fDeep)
+        {
+            pMod->Bind.pNext = NULL;
+            pMod->Bind.pPrev = g_pkLdrDyldBindTail;
+            if (g_pkLdrDyldBindTail)
+                g_pkLdrDyldBindTail->Bind.pNext = pMod;
+            else
+                g_pkLdrDyldBindHead = pMod;
+            g_pkLdrDyldBindTail = pMod;
+        }
+        else
+        {
+            pMod->Bind.pPrev = NULL;
+            pMod->Bind.pNext = g_pkLdrDyldBindHead;
+            if (g_pkLdrDyldBindHead)
+                g_pkLdrDyldBindHead->Bind.pPrev = pMod;
+            else
+                g_pkLdrDyldBindTail = pMod;
+            g_pkLdrDyldBindHead = pMod;
+        }
+    }
+}
+
+
+/**
+ * Marks a module as not bindable, i.e. it will not be considered when
+ * resolving names the unix way.
+ *
+ * @param   pMod    The module.
+ */
+void kldrDyldModClearBindable(PKLDRDYLDMOD pMod)
+{
+    KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_DESTROY);
+    if (pMod->fBindable)
+    {
+        pMod->fBindable = 0;
+        if (pMod->Bind.pPrev)
+            pMod->Bind.pPrev->Bind.pNext = pMod->Bind.pNext;
+        else
+            g_pkLdrDyldBindHead = pMod->Bind.pNext;
+        if (pMod->Bind.pNext)
+            pMod->Bind.pNext->Bind.pPrev = pMod->Bind.pPrev;
+        else
+            g_pkLdrDyldBindTail = pMod->Bind.pPrev;
+        pMod->Bind.pNext = NULL;
+        pMod->Bind.pPrev = NULL;
+    }
+}
+
+
+/**
+ * Marks the module as global instead of being specific.
+ *
+ * A global module can be a matching result when the request
+ * doesn't specify a path. A specific module will not match
+ * unless the path also matches.
+ *
+ * @param   pMod    The module.
+ */
+void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod)
+{
+    pMod->fGlobalOrSpecific = 1;
+}
+
+
+/**
+ * Marks the module as specific instead of global.
+ *
+ * See kldrDyldModMarkGlobal for an explanation of the two terms.
+ *
+ * @param   pMod    The module.
+ */
+void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod)
+{
+    pMod->fGlobalOrSpecific = 0;
+}
+
+
+/**
+ * Adds a reference to the module making sure it won't be freed just yet.
+ *
+ * @param   pMod    The module.
+ */
+void kldrDyldModAddRef(PKLDRDYLDMOD pMod)
+{
+    pMod->cRefs++;
+}
+
+
+/**
+ * Dereference a module.
+ *
+ * @param   pMod
+ */
+void kldrDyldModDeref(PKLDRDYLDMOD pMod)
+{
+    /* validate input */
+    KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
+    KLDRDYLDMOD_ASSERT(pMod->cRefs >= pMod->cDepRefs + pMod->cDynRefs);
+    KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END);
+
+    /* decrement. */
+    if (pMod->cRefs > 0)
+        pMod->cRefs--;
+
+    /* execute delayed freeing. */
+    if (    pMod->enmState == KLDRSTATE_DESTROYED
+        &&  !pMod->cRefs)
+    {
+        pMod->u32MagicHead = 1;
+        pMod->u32MagicTail = 2;
+        kHlpFree(pMod);
+    }
+}
+
+
+/**
+ * Increment the count of modules depending on this module.
+ *
+ * @param   pMod    The module.
+ * @param   pDep    The module which depends on us.
+ */
+void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep)
+{
+    (void)pDep;
+
+    /* validate state */
+    switch (pMod->enmState)
+    {
+        case KLDRSTATE_MAPPED:
+        case KLDRSTATE_RELOADED:
+        case KLDRSTATE_LOADED_PREREQUISITES:
+        case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
+        case KLDRSTATE_PENDING_INITIALIZATION:
+        case KLDRSTATE_INITIALIZING:
+        case KLDRSTATE_GOOD:
+            break;
+        default:
+            KLDRDYLDMOD_ASSERT(!"invalid state");
+            break;
+
+    }
+    KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END);
+    pMod->cRefs++;
+    pMod->cDepRefs++;
+}
+
+
+/**
+ * Drop a dependency.
+ *
+ * @param   pMod    The module.
+ * @param   pDep    The module which depends on us.
+ */
+void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep)
+{
+    KLDRDYLDMOD_ASSERT(pMod->cDepRefs > 0);
+    if (pMod->cDepRefs == 0)
+        return;
+    KLDRDYLDMOD_ASSERT(pMod->cDepRefs <= pMod->cRefs);
+    KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_MAPPED && pMod->enmState <= KLDRSTATE_PENDING_DESTROY);
+
+    pMod->cRefs--;
+    pMod->cDepRefs--;
+    if (    pMod->cDepRefs > 0
+        ||  pMod->cDynRefs > 0)
+        return;
+
+    /*
+     * The module should be unloaded.
+     */
+    kldrDyldModUnloadPrerequisites(pMod);
+}
+
+
+/**
+ * Increment the dynamic load count.
+ *
+ * @returns 0
+ * @param   pMod    The module.
+ */
+int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod)
+{
+    KLDRDYLDMOD_ASSERT(     pMod->enmState == KLDRSTATE_GOOD
+                       ||   pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION
+                       ||   pMod->enmState == KLDRSTATE_INITIALIZING);
+    pMod->cRefs++;
+    pMod->cDynRefs++;
+    return 0;
+}
+
+
+/**
+ * Decrement the dynamic load count of the module and unload the module
+ * if the total reference count reaches zero.
+ *
+ * This may cause a cascade of unloading to occure. See kldrDyldModUnloadPrerequisites().
+ *
+ * @returns status code.
+ * @retval  0 on success.
+ * @retval  KLDR_ERR_NOT_LOADED_DYNAMICALLY if the module wasn't loaded dynamically.
+ * @param   pMod        The module to unload.
+ */
+int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod)
+{
+    if (pMod->cDynRefs == 0)
+        return KLDR_ERR_NOT_LOADED_DYNAMICALLY;
+    KLDRDYLDMOD_ASSERT(pMod->cDynRefs <= pMod->cRefs);
+    KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
+
+    pMod->cRefs--;
+    pMod->cDynRefs--;
+    if (    pMod->cDynRefs > 0
+        ||  pMod->cDepRefs > 0)
+        return 0;
+
+    /*
+     * The module should be unloaded.
+     */
+    kldrDyldModUnloadPrerequisites(pMod);
+    return 0;
+}
+
+
+/**
+ * Worker for kldrDyldModUnloadPrerequisites.
+ *
+ * @returns The number of modules that now can be unloaded.
+ * @param   pMod    The module in  question.
+ */
+static KU32 kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod)
+{
+    PKLDRDYLDMOD    pMod2;
+    KU32            cToUnload = 0;
+    KU32            i;
+
+    KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs);
+
+    /*
+     * Release the one in this module.
+     */
+    for (i = 0; i < pMod->cPrereqs; i++)
+    {
+        pMod2 = pMod->papPrereqs[i];
+        if (pMod2)
+        {
+            pMod->papPrereqs[i] = NULL;
+
+            /* do the derefering ourselves or we'll end up in a recursive loop here. */
+            KLDRDYLDMOD_ASSERT(pMod2->cDepRefs > 0);
+            KLDRDYLDMOD_ASSERT(pMod2->cRefs >= pMod2->cDepRefs);
+            pMod2->cDepRefs--;
+            pMod2->cRefs--;
+            cToUnload += !pMod2->cDepRefs && !pMod2->cDynRefs;
+        }
+    }
+
+    /*
+     * Change the state
+     */
+    switch (pMod->enmState)
+    {
+        case KLDRSTATE_LOADED_PREREQUISITES:
+        case KLDRSTATE_FIXED_UP:
+            pMod->enmState = KLDRSTATE_PENDING_DESTROY;
+            kldrDyldModUnlink(pMod);
+            break;
+
+        case KLDRSTATE_PENDING_INITIALIZATION:
+            pMod->enmState = KLDRSTATE_PENDING_GC;
+            break;
+
+        case KLDRSTATE_RELOADED_FIXED_UP:
+        case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
+        case KLDRSTATE_GOOD:
+            pMod->enmState = KLDRSTATE_PENDING_TERMINATION;
+            break;
+
+        case KLDRSTATE_INITIALIZATION_FAILED:
+            break;
+
+        default:
+            KLDRDYLDMOD_ASSERT(!"invalid state");
+            break;
+    }
+
+    return cToUnload;
+}
+
+
+/**
+ * This is the heart of the unload code.
+ *
+ * It will recursivly (using the load list) initiate module unloading
+ * of all affected modules.
+ *
+ * This function will cause a state transition to PENDING_DESTROY, PENDING_GC
+ * or PENDING_TERMINATION depending on the module state. There is one exception
+ * to this, and that's INITIALIZATION_FAILED, where the state will not be changed.
+ *
+ * @param   pMod        The module which prerequisites should be unloaded.
+ */
+void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod)
+{
+    KU32            cToUnload;
+
+    /* sanity */
+#ifdef KLDRDYLD_STRICT
+    {
+    PKLDRDYLDMOD pMod2;
+    for (pMod2 = kLdrDyldHead; pMod2; pMod2 = pMod2->Load.pNext)
+        KLDRDYLDMOD_ASSERT(pMod2->enmState != KLDRSTATE_GOOD || pMod2->cRefs);
+    }
+#endif
+    KLDRDYLDMOD_ASSERT(pMod->papPrereqs);
+
+    /*
+     * Unload prereqs of the module we're called on first.
+     */
+    cToUnload = kldrDyldModUnloadPrerequisitesOne(pMod);
+
+    /*
+     * Iterate the load list in a cyclic manner until there are no more
+     * modules that can be pushed on into unloading.
+     */
+    while (cToUnload)
+    {
+        cToUnload = 0;
+        for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
+        {
+            if (    pMod->cDepRefs
+                ||  pMod->cDynRefs
+                ||  pMod->enmState >= KLDRSTATE_PENDING_TERMINATION
+                ||  pMod->enmState < KLDRSTATE_LOADED_PREREQUISITES)
+                continue;
+            cToUnload += kldrDyldModUnloadPrerequisitesOne(pMod);
+        }
+    }
+}
+
+
+/**
+ * Loads the prerequisite modules this module depends on.
+ *
+ * To find each of the prerequisite modules this method calls
+ * kldrDyldGetPrerequisite() and it will make sure the modules
+ * are added to the load stack frame.
+ *
+ * @returns 0 on success, non-zero native OS or kLdr status code on failure.
+ *          The state is changed to LOADED_PREREQUISITES or RELOADED_LOADED_PREREQUISITES.
+ * @param   pMod            The module.
+ * @param   pszPrefix       Prefix to use when searching.
+ * @param   pszSuffix       Suffix to use when searching.
+ * @param   enmSearch       Method to use when locating the module and any modules it may depend on.
+ * @param   fFlags          Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
+ */
+int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
+                                 KLDRDYLDSEARCH enmSearch, unsigned fFlags)
+{
+    KI32    cPrereqs;
+    KU32    i;
+    int     rc = 0;
+
+    /* sanity */
+    switch (pMod->enmState)
+    {
+        case KLDRSTATE_MAPPED:
+        case KLDRSTATE_RELOADED:
+            break;
+        default:
+            KLDRDYLDMOD_ASSERT(!"invalid state");
+            return -1;
+    }
+
+    /*
+     * Query number of prerequiste modules and allocate the array.
+     */
+    cPrereqs = kLdrModNumberOfImports(pMod->pMod, NULL);
+    kHlpAssert(cPrereqs >= 0);
+    if (pMod->cPrereqs != cPrereqs)
+    {
+        KLDRDYLDMOD_ASSERT(!pMod->papPrereqs);
+        pMod->papPrereqs = (PPKLDRDYLDMOD)kHlpAllocZ(sizeof(pMod->papPrereqs[0]) * cPrereqs);
+        if (!pMod->papPrereqs)
+            return KERR_NO_MEMORY;
+        pMod->cPrereqs = cPrereqs;
+    }
+    else
+        KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs);
+
+    /*
+     * Iterate the prerequisites and load them.
+     */
+    for (i = 0; i < pMod->cPrereqs; i++)
+    {
+        static char s_szPrereq[260];
+        PKLDRDYLDMOD pPrereqMod;
+
+        KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL);
+        rc = kLdrModGetImport(pMod->pMod, NULL, i, s_szPrereq, sizeof(s_szPrereq));
+        if (rc)
+            break;
+        rc = kldrDyldGetPrerequisite(s_szPrereq, pszPrefix, pszSuffix, enmSearch, fFlags, pMod, &pPrereqMod);
+        if (rc)
+            break;
+        pMod->papPrereqs[i] = pPrereqMod;
+    }
+
+    /* change the state regardless of what happend. */
+    if (pMod->enmState == KLDRSTATE_MAPPED)
+        pMod->enmState = KLDRSTATE_LOADED_PREREQUISITES;
+    else
+        pMod->enmState = KLDRSTATE_RELOADED_LOADED_PREREQUISITES;
+    return rc;
+}
+
+
+/**
+ * Maps an open module.
+ *
+ * On success the module will be in the MAPPED state.
+ *
+ * @returns 0 on success, non-zero native OS or kLdr status code on failure.
+ * @param   pMod    The module which needs to be unmapped and set pending for destruction.
+ */
+int kldrDyldModMap(PKLDRDYLDMOD pMod)
+{
+    int rc;
+
+    /* sanity */
+    KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_OPEN);
+    KLDRDYLDMOD_ASSERT(!pMod->fMapped);
+    if (pMod->fMapped)
+        return 0;
+
+    /* do the job. */
+    rc = kLdrModMap(pMod->pMod);
+    if (!rc)
+    {
+        rc = kLdrModAllocTLS(pMod->pMod);
+        if (!rc)
+        {
+            /** @todo TLS */
+            pMod->fMapped = 1;
+            pMod->enmState = KLDRSTATE_MAPPED;
+        }
+        else
+            kLdrModUnmap(pMod->pMod);
+    }
+    return rc;
+}
+
+
+/**
+ * Unmaps the module, unlinks it from everywhere marks it PENDING_DESTROY.
+ *
+ * @returns 0 on success, non-zero native OS or kLdr status code on failure.
+ * @param   pMod    The module which needs to be unmapped and set pending for destruction.
+ */
+int kldrDyldModUnmap(PKLDRDYLDMOD pMod)
+{
+    int rc;
+
+    /* sanity */
+    KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
+    KLDRDYLDMOD_ASSERT(pMod->fMapped);
+    switch (pMod->enmState)
+    {
+        case KLDRSTATE_MAPPED:
+        case KLDRSTATE_GC:
+        case KLDRSTATE_PENDING_DESTROY:
+            break;
+        default:
+            KLDRDYLDMOD_ASSERT(!"invalid state");
+            return -1;
+    }
+
+    /* do the job. */
+    if (pMod->fAllocatedTLS)
+    {
+        kLdrModFreeTLS(pMod->pMod);
+        pMod->fAllocatedTLS = 0;
+    }
+    rc = kLdrModUnmap(pMod->pMod);
+    if (!rc)
+    {
+        pMod->fMapped = 0;
+        if (pMod->enmState < KLDRSTATE_PENDING_DESTROY)
+        {
+            pMod->enmState = KLDRSTATE_PENDING_DESTROY;
+            kldrDyldModUnlink(pMod);
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ * Reloads the module.
+ *
+ * Reloading means that all modified pages are restored to their original
+ * state. Whether this includes the code segments depends on whether the fixups
+ * depend on the addend in the place they are fixing up - so it's format specific.
+ *
+ * @returns 0 on success, non-zero native OS or kLdr status code on failure.
+ * @param   pMod    The module which needs to be unmapped and set pending for destruction.
+ */
+int kldrDyldModReload(PKLDRDYLDMOD pMod)
+{
+    int rc;
+
+    /* sanity */
+    KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
+    KLDRDYLDMOD_ASSERT(pMod->fMapped);
+
+    switch (pMod->enmState)
+    {
+        case KLDRSTATE_MAPPED:
+        case KLDRSTATE_GC:
+        case KLDRSTATE_PENDING_DESTROY:
+            break;
+        default:
+            KLDRDYLDMOD_ASSERT(!"invalid state");
+            return -1;
+    }
+
+    /* Free TLS before reloading. */
+    if (pMod->fAllocatedTLS)
+    {
+        kLdrModFreeTLS(pMod->pMod);
+        pMod->fAllocatedTLS = 0;
+    }
+
+    /* Let the module interpreter do the reloading of the mapping. */
+    rc = kLdrModReload(pMod->pMod);
+    if (!rc)
+    {
+        rc = kLdrModAllocTLS(pMod->pMod);
+        if (!rc)
+        {
+            pMod->fAllocatedTLS = 1;
+            pMod->enmState = KLDRSTATE_RELOADED;
+        }
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc FNKLDRMODGETIMPORT
+ * pvUser points to the KLDRDYLDMOD.
+ */
+static int kldrDyldModFixupGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol,
+                                             const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                                             PKLDRADDR puValue, KU32 *pfKind, void *pvUser)
+{
+    static int s_cRecursiveCalls = 0;
+    PKLDRDYLDMOD pDyldMod = (PKLDRDYLDMOD)pvUser;
+    int rc;
+
+    /* guard against too deep forwarder recursion. */
+    if (s_cRecursiveCalls >= 5)
+        return KLDR_ERR_TOO_LONG_FORWARDER_CHAIN;
+    s_cRecursiveCalls++;
+
+    if (iImport != NIL_KLDRMOD_IMPORT)
+    {
+        /* specific import module search. */
+        PKLDRDYLDMOD pPrereqMod;
+
+        KLDRDYLDMOD_ASSERT(iImport < pDyldMod->cPrereqs);
+        pPrereqMod = pDyldMod->papPrereqs[iImport];
+
+        KLDRDYLDMOD_ASSERT(pPrereqMod);
+        KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicHead == KLDRDYMOD_MAGIC);
+        KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicTail == KLDRDYMOD_MAGIC);
+        KLDRDYLDMOD_ASSERT(pPrereqMod->enmState < KLDRSTATE_TERMINATING);
+
+        rc = kLdrModQuerySymbol(pPrereqMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
+                                iSymbol, pchSymbol, cchSymbol, pszVersion,
+                                kldrDyldModFixupGetImportCallback, pPrereqMod, puValue, pfKind);
+        if (rc)
+        {
+            if (pchSymbol)
+                kldrDyldFailure(rc, "%s[%d]->%s.%.*s%s", pDyldMod->pMod->pszName, iImport,
+                                pPrereqMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : "");
+            else
+                kldrDyldFailure(rc, "%s[%d]->%s.%d%s", pDyldMod->pMod->pszName, iImport,
+                                pPrereqMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : "");
+        }
+    }
+    else
+    {
+        /* bind list search. */
+        unsigned fFound = 0;
+        PKLDRDYLDMOD pBindMod = g_pkLdrDyldBindHead;
+        rc = 0;
+        while (pBindMod)
+        {
+            KU32 fKind;
+            KLDRADDR uValue;
+            rc = kLdrModQuerySymbol(pBindMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
+                                    iSymbol, pchSymbol, cchSymbol, pszVersion,
+                                    kldrDyldModFixupGetImportCallback, pBindMod, &uValue, &fKind);
+            if (    !rc
+                &&  (   !fFound
+                     || !(fKind & KLDRSYMKIND_WEAK)
+                    )
+               )
+            {
+                *pfKind = fKind;
+                *puValue = uValue;
+                fFound = 1;
+                if (!(fKind & KLDRSYMKIND_WEAK))
+                    break;
+            }
+
+            /* next */
+            pBindMod = pBindMod->Bind.pNext;
+        }
+        rc = fFound ? 0 : KLDR_ERR_SYMBOL_NOT_FOUND;
+        if (!fFound)
+        {
+            if (pchSymbol)
+                kldrDyldFailure(rc, "%s->%.*s%s", pDyldMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : "");
+            else
+                kldrDyldFailure(rc, "%s->%d%s", pDyldMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : "");
+        }
+    }
+
+    s_cRecursiveCalls--;
+    return rc;
+}
+
+
+/**
+ * Applies fixups to a module which prerequisistes has been
+ * successfully loaded.
+ *
+ * @returns 0 on success, non-zero native OS or kLdr status code on failure.
+ * @param   pMod    The module which needs to be unmapped and set pending for destruction.
+ */
+int kldrDyldModFixup(PKLDRDYLDMOD pMod)
+{
+    int rc;
+
+    /* sanity */
+    KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
+    KLDRDYLDMOD_ASSERT(     pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
+                       ||   pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES);
+
+    /* do the job */
+    rc = kLdrModFixupMapping(pMod->pMod, kldrDyldModFixupGetImportCallback, pMod);/** @todo fixme. */
+    if (!rc)
+        pMod->enmState = KLDRSTATE_FIXED_UP;
+    return rc;
+}
+
+
+/**
+ * Calls the module initialization entry point if any.
+ *
+ * This is considered to be a module specific thing and leave if
+ * to the module interpreter. They will have to deal with different
+ * module init practices between platforms should there be any.
+ *
+ * @returns 0 and state changed to GOOD on success.
+ *          Non-zero OS or kLdr status code and status changed to INITIALIZATION_FAILED on failure.
+ * @param   pMod        The module that should be initialized.
+ */
+int kldrDyldModCallInit(PKLDRDYLDMOD pMod)
+{
+    int rc;
+
+    KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION);
+    KLDRDYLDMOD_ASSERT(!pMod->fInitList);
+
+    pMod->enmState = KLDRSTATE_INITIALIZING;
+    rc = kLdrModCallInit(pMod->pMod, (KUPTR)pMod->hMod);
+    if (!rc)
+    {
+        pMod->enmState = KLDRSTATE_GOOD;
+        /* push it onto the termination list.*/
+        pMod->InitTerm.pPrev = NULL;
+        pMod->InitTerm.pNext = g_pkLdrDyldTermHead;
+        if (g_pkLdrDyldTermHead)
+            g_pkLdrDyldTermHead->InitTerm.pPrev = pMod;
+        else
+            g_pkLdrDyldTermTail = pMod;
+        g_pkLdrDyldTermHead = pMod;
+    }
+    else
+        pMod->enmState = KLDRSTATE_INITIALIZATION_FAILED;
+
+    return rc;
+}
+
+
+/**
+ * Calls the module termination entry point if any.
+ *
+ * This'll change the module status to PENDING_GC.
+ *
+ * @param   pMod        The module that should be initialized.
+ */
+void kldrDyldModCallTerm(PKLDRDYLDMOD pMod)
+{
+    KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_TERMINATION);
+
+    pMod->enmState = KLDRSTATE_TERMINATING;
+    kLdrModCallTerm(pMod->pMod, (KUPTR)pMod->hMod);
+    pMod->enmState = KLDRSTATE_PENDING_GC;
+    /* unlinking on destruction. */
+}
+
+
+/**
+ * Calls the thread attach entry point if any.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   pMod        The module.
+ */
+int kldrDyldModAttachThread(PKLDRDYLDMOD pMod)
+{
+    KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
+
+    return kLdrModCallThread(pMod->pMod, (KUPTR)pMod->hMod, 1 /* attach */);
+}
+
+
+/**
+ * Calls the thread detach entry point if any.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   pMod        The module.
+ */
+void kldrDyldModDetachThread(PKLDRDYLDMOD pMod)
+{
+    KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
+
+    kLdrModCallThread(pMod->pMod, (KUPTR)pMod->hMod, 0 /* detach */);
+}
+
+
+/**
+ * Gets the main stack, allocate it if necessary.
+ *
+ * @returns 0 on success, non-zero native OS or kLdr status code on failure.
+ * @param   pMod        The module.
+ * @param   ppvStack    Where to store the address of the stack (lowest address).
+ * @param   pcbStack    Where to store the size of the stack.
+ */
+int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, KSIZE *pcbStack)
+{
+    int rc = 0;
+    KLDRSTACKINFO StackInfo;
+    KLDRDYLDMOD_ASSERT(pMod->fExecutable);
+
+    /*
+     * Since we might have to allocate the stack ourselves, and there will only
+     * ever be one main stack, we'll be keeping the main stack info in globals.
+     */
+    if (!g_fkLdrDyldDoneMainStack)
+    {
+        rc = kLdrModGetStackInfo(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &StackInfo);
+        if (!rc)
+        {
+            /* check if there is a stack size override/default. */
+            KSIZE cbDefOverride;
+            if (kHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride))
+                cbDefOverride = 0;
+
+
+            /* needs allocating? */
+            if (    StackInfo.LinkAddress == NIL_KLDRADDR
+                ||  StackInfo.cbStack < cbDefOverride)
+            {
+                KSIZE cbStack = (KSIZE)K_MAX(StackInfo.cbStack, cbDefOverride);
+
+                g_pvkLdrDyldMainStack = kldrDyldOSAllocStack(cbStack);
+                if (g_pvkLdrDyldMainStack)
+                {
+                    g_cbkLdrDyldMainStack = cbStack;
+                    g_fkLdrDyldMainStackAllocated = 1;
+                }
+                else
+                    rc = KLDR_ERR_MAIN_STACK_ALLOC_FAILED;
+            }
+            else
+            {
+                KLDRDYLDMOD_ASSERT(StackInfo.Address != NIL_KLDRADDR);
+                KLDRDYLDMOD_ASSERT(StackInfo.cbStack > 0);
+
+                g_fkLdrDyldMainStackAllocated = 0;
+                g_pvkLdrDyldMainStack = (void *)(KUPTR)StackInfo.Address;
+                KLDRDYLDMOD_ASSERT((KUPTR)g_pvkLdrDyldMainStack == StackInfo.Address);
+
+                g_cbkLdrDyldMainStack = (KSIZE)StackInfo.cbStack;
+                KLDRDYLDMOD_ASSERT(StackInfo.cbStack == g_cbkLdrDyldMainStack);
+            }
+        }
+        if (!rc)
+            g_fkLdrDyldDoneMainStack = 1;
+    }
+
+    if (!rc)
+    {
+        if (ppvStack)
+            *ppvStack = g_pvkLdrDyldMainStack;
+        if (pcbStack)
+            *pcbStack = g_cbkLdrDyldMainStack;
+    }
+
+    return rc;
+}
+
+
+/**
+ * This starts the executable module.
+ *
+ * @returns non-zero OS or kLdr status code on failure.
+ *          (won't return on success.)
+ * @param   pMod    The executable module.
+ */
+int kldrDyldModStartExe(PKLDRDYLDMOD pMod)
+{
+    int         rc;
+    KLDRADDR    MainEPAddress;
+    void       *pvStack;
+    KSIZE      cbStack;
+    KLDRDYLDMOD_ASSERT(pMod->fExecutable);
+
+    rc = kLdrModQueryMainEntrypoint(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &MainEPAddress);
+    if (rc)
+        return rc;
+    rc = kldrDyldModGetMainStack(pMod, &pvStack, &cbStack);
+    if (rc)
+        return rc;
+    return kldrDyldOSStartExe((KUPTR)MainEPAddress, pvStack, cbStack);
+}
+
+
+/**
+ * Gets the module name.
+ *
+ * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure.
+ * @param   pMod            The module.
+ * @param   pszName         Where to store the name.
+ * @param   cchName         The size of the name buffer.
+ */
+int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName)
+{
+    KSIZE cch = K_MIN(cchName, pMod->pMod->cchName + 1);
+    if (cch)
+    {
+        kHlpMemCopy(pszName, pMod->pMod->pszName, cch - 1);
+        pszName[cch - 1] = '\0';
+    }
+    return cchName <= pMod->pMod->cchName ? KERR_BUFFER_OVERFLOW : 0;
+}
+
+
+/**
+ * Gets the module filename.
+ *
+ * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure.
+ * @param   pMod            The module.
+ * @param   pszFilename     Where to store the filename.
+ * @param   cchFilename     The size of the filename buffer.
+ */
+int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename)
+{
+    KSIZE cch = K_MIN(cchFilename, pMod->pMod->cchFilename + 1);
+    if (cch)
+    {
+        kHlpMemCopy(pszFilename, pMod->pMod->pszFilename, cch - 1);
+        pszFilename[cch - 1] = '\0';
+    }
+    return cchFilename <= pMod->pMod->cchFilename ? KERR_BUFFER_OVERFLOW : 0;
+}
+
+
+/**
+ * Gets the address/value of a symbol in the specified module.
+ *
+ * @returns 0 on success, KLDR_ERR_SYMBOL_NOT_FOUND on failure.
+ * @param   pMod            The module.
+ * @param   uSymbolOrdinal  The symbol ordinal 0. This is ignored if the name is non-zero.
+ * @param   pszSymbolName   The symbol name. Can be NULL.
+ * @param   puValue         Where to store the value. optional.
+ * @param   pfKind          Where to store the symbol kind. optional.
+ */
+int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName,
+                           KUPTR *puValue, KU32 *pfKind)
+{
+    int         rc;
+    KLDRADDR    uValue = 0;
+    KU32        fKind = 0;
+
+    rc = kLdrModQuerySymbol(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP,
+                            uSymbolOrdinal, pszSymbolName, kHlpStrLen(pszSymbolName), NULL,
+                            kldrDyldModFixupGetImportCallback, pMod,
+                            &uValue, &fKind);
+    if (!rc)
+    {
+        if (puValue)
+        {
+            *puValue = (KUPTR)uValue;
+            KLDRDYLDMOD_ASSERT(*puValue == uValue);
+        }
+        if (pfKind)
+            *pfKind = fKind;
+    }
+
+    return rc;
+}
+
Index: /trunk/kLdr/kLdrDyldOS.c
===================================================================
--- /trunk/kLdr/kLdrDyldOS.c	(revision 2)
+++ /trunk/kLdr/kLdrDyldOS.c	(revision 2)
@@ -0,0 +1,135 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader, OS specific operations.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# undef IMAGE_DOS_SIGNATURE
+# undef IMAGE_NT_SIGNATURE
+# include <Windows.h>
+
+#else
+# include <k/kHlpAlloc.h>
+
+#endif
+
+
+/**
+ * Allocates a stack.
+ *
+ * @returns Pointer to the stack. NULL on allocation failure (assumes out of memory).
+ * @param   cb      The size of the stack. This shall be page aligned.
+ *                  If 0, a OS specific default stack size will be employed.
+ */
+void *kldrDyldOSAllocStack(KSIZE cb)
+{
+#if K_OS == K_OS_OS2
+    APIRET rc;
+    PVOID pv;
+
+    if (!cb)
+        cb = 1 * 1024*1024; /* 1MB */
+
+    rc = DosAllocMem(&pv, cb, OBJ_TILE | PAG_COMMIT | PAG_WRITE | PAG_READ);
+    if (rc == NO_ERROR)
+        return pv;
+    return NULL;
+
+#elif K_OS == K_OS_WINDOWS
+
+    if (!cb)
+        cb = 1 *1024*1024; /* 1MB */
+
+    return VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_READWRITE);
+
+#else
+    void *pv;
+
+    if (!cb)
+        cb = 1 * 1024*1024; /* 1MB */
+
+    if (!kHlpPageAlloc(&pv, cb, KPROT_READWRITE, K_FALSE))
+        return pv;
+    return NULL;
+#endif
+}
+
+
+/**
+ * Invokes the main executable entry point with whatever
+ * parameters specific to the host OS and/or module format.
+ *
+ * @returns
+ * @param   uMainEPAddress  The address of the main entry point.
+ * @param   pvStack         Pointer to the stack object.
+ * @param   cbStack         The size of the stack object.
+ */
+int kldrDyldOSStartExe(KUPTR uMainEPAddress, void *pvStack, KSIZE cbStack)
+{
+#if K_OS == K_OS_WINDOWS
+    /*
+     * Invoke the entrypoint on the current stack for now.
+     * Deal with other formats and stack switching another day.
+     */
+    int rc;
+    int (*pfnEP)(void);
+    pfnEP = (int (*)(void))uMainEPAddress;
+
+    rc = pfnEP();
+
+    TerminateProcess(GetCurrentProcess(), rc);
+    kHlpAssert(!"TerminateProcess failed");
+    for (;;)
+        TerminateProcess(GetCurrentProcess(), rc);
+#endif
+
+    return -1;
+}
+
+
+void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack)
+{
+    /*kHlpAssert(!"not implemented");*/
+
+    /** @todo implement this properly! */
+    kldrDyldDoLoadExe(pExe);
+}
+
Index: /trunk/kLdr/kLdrDyldSem.c
===================================================================
--- /trunk/kLdr/kLdrDyldSem.c	(revision 2)
+++ /trunk/kLdr/kLdrDyldSem.c	(revision 2)
@@ -0,0 +1,199 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader, Semaphore Helper Functions.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kDefs.h>
+#include <k/kHlpSem.h>
+#include <k/kHlpAssert.h>
+
+#if K_OS == K_OS_DARWIN
+# include <mach/mach.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+
+#elif  K_OS == K_OS_WINDOWS
+# include <Windows.h>
+
+#else
+# error "port me"
+#endif
+
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+#if K_OS == K_OS_DARWIN
+/** The loader sempahore. */
+static semaphore_t      g_Semaphore = MACH_PORT_NULL;
+
+#elif K_OS == K_OS_OS2
+/** The loader sempahore. */
+static HMTX             g_hmtx;
+
+#elif  K_OS == K_OS_WINDOWS
+/** The loader sempahore. */
+static CRITICAL_SECTION g_CritSect;
+
+#else
+# error "port me"
+#endif
+
+
+/**
+ * Initializes the loader semaphore.
+ *
+ * @returns 0 on success, non-zero OS status code on failure.
+ */
+int kLdrDyldSemInit(void)
+{
+#if K_OS == K_OS_DARWIN
+    kern_return_t krc;
+
+    krc = semaphore_create(mach_task_self(), &g_Semaphore, SYNC_POLICY_FIFO, 0);
+    if (krc != KERN_SUCCESS)
+        return krc;
+
+#elif K_OS == K_OS_OS2
+    APIRET rc;
+    g_hmtx = NULLHANDLE;
+    rc = DosCreateMutexSem(NULL, &g_hmtx, 0, FALSE);
+    if (rc)
+        return rc;
+
+#elif  K_OS == K_OS_WINDOWS
+    InitializeCriticalSection(&g_CritSect);
+
+#else
+# error "port me"
+#endif
+    return 0;
+}
+
+
+/**
+ * Terminates the loader semaphore.
+ */
+void kLdrDyldSemTerm(void)
+{
+#if K_OS == K_OS_DARWIN
+    kern_return_t krc;
+    semaphore_t Semaphore = g_Semaphore;
+    g_Semaphore = MACH_PORT_NULL;
+    krc = semaphore_destroy(mach_task_self(), Semaphore);
+    kHlpAssert(krc == KERN_SUCCESS); (void)krc;
+
+#elif K_OS == K_OS_OS2
+    HMTX hmtx = g_hmtx;
+    g_hmtx = NULLHANDLE;
+    DosCloseMutexSem(hmtx);
+
+#elif  K_OS == K_OS_WINDOWS
+    DeleteCriticalSection(&g_CritSect);
+
+#else
+# error "port me"
+#endif
+}
+
+
+/**
+ * Requests the loader sempahore ownership.
+ * This can be done recursivly.
+ *
+ * @returns 0 on success, non-zero OS status code on failure.
+ */
+int kLdrDyldSemRequest(void)
+{
+#if K_OS == K_OS_DARWIN
+    /* not sure about this... */
+    kern_return_t krc;
+    do krc = semaphore_wait(g_Semaphore);
+    while (krc == KERN_ABORTED);
+    if (krc == KERN_SUCCESS)
+        return 0;
+    return krc;
+
+#elif K_OS == K_OS_OS2
+    APIRET rc = DosRequestMutexSem(g_hmtx, 5000);
+    if (rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_INTERRUPT)
+    {
+        unsigned i = 0;
+        do
+        {
+            /** @todo check for deadlocks etc. */
+            rc = DosRequestMutexSem(g_hmtx, 1000);
+        } while (   (   rc == ERROR_TIMEOUT
+                     || rc == ERROR_SEM_TIMEOUT
+                     || rc == ERROR_INTERRUPT)
+                 && i++ < 120);
+    }
+    return rc;
+
+#elif  K_OS == K_OS_WINDOWS
+    EnterCriticalSection(&g_CritSect);
+    return 0;
+
+#else
+# error "port me"
+#endif
+}
+
+
+/**
+ * Releases the loader semaphore ownership.
+ * The caller is responsible for making sure it's the semaphore owner!
+ */
+void kLdrDyldSemRelease(void)
+{
+#if K_OS == K_OS_DARWIN
+    /* not too sure about this... */
+    kern_return_t krc = semaphore_signal(g_Semaphore);
+    kHlpAssert(krc == KERN_SUCCESS); (void)krc;
+
+#elif K_OS == K_OS_OS2
+    APIRET rc = DosReleaseMutexSem(g_hmtx);
+    kHlpAssert(!rc); (void)rc;
+
+#elif  K_OS == K_OS_WINDOWS
+    LeaveCriticalSection(&g_CritSect);
+
+#else
+# error "port me"
+#endif
+}
+
Index: /trunk/kLdr/kLdrExeStub-os2.asm
===================================================================
--- /trunk/kLdr/kLdrExeStub-os2.asm	(revision 2)
+++ /trunk/kLdr/kLdrExeStub-os2.asm	(revision 2)
@@ -0,0 +1,74 @@
+; $Id$
+;; @file
+; kLdr - OS/2 Loader Stub.
+;
+; This file contains a 64kb code/data/stack segment which is used to kick off
+; the loader dll that loads the process.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; In addition to the permissions in the GNU Lesser General Public
+; License, you are granted unlimited permission to link the compiled
+; version of this file into combinations with other programs, and to
+; distribute those combinations without any restriction coming from
+; the use of this file.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA
+;
+
+struc KLDRARGS
+    .fFlags         resd 1
+    .enmSearch      resd 1
+    .szExecutable   resb 260
+    .szDefPrefix    resb 16
+    .szDefSuffix    resb 16
+    .szLibPath      resb (4096 - (4 + 4 + 16 + 16 + 260))
+endstruc
+
+extern _kLdrDyldLoadExe
+
+
+segment DATA32 stack CLASS=DATA align=16 use32
+..start:
+    push    args
+    jmp     _kLdrDyldLoadExe
+
+;
+; Argument structure.
+;
+align 4
+args:
+istruc KLDRARGS
+    at KLDRARGS.fFlags,         dd 0
+    at KLDRARGS.enmSearch,      dd 2 ;KLDRDYLD_SEARCH_HOST
+    at KLDRARGS.szDefPrefix,    db ''
+    at KLDRARGS.szDefSuffix,    db '.dll'
+;    at KLDRARGS.szExecutable,   db 'tst-0.exe'
+    at KLDRARGS.szLibPath,      db ''
+iend
+
+segment STACK32 stack CLASS=STACK align=16 use32
+; pad up to 64KB.
+resb 60*1024
+
+global WEAK$ZERO
+WEAK$ZERO EQU 0
+group DGROUP, DATA32  STACK32
+
Index: /trunk/kLdr/kLdrExeStub-os2.c
===================================================================
--- /trunk/kLdr/kLdrExeStub-os2.c	(revision 2)
+++ /trunk/kLdr/kLdrExeStub-os2.c	(revision 2)
@@ -0,0 +1,61 @@
+/* $Id$ */
+/** @file
+ * kLdr - OS/2 C Loader Stub.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include <os2.h>
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The stub arguments. */
+static const KLDREXEARGS g_Args =
+{
+    /* .fFlags       = */ KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT,
+    /* .enmSearch    = */ KLDRDYLD_SEARCH_OS2,
+    /* .szExecutable = */ "tst-0", /* just while testing */
+    /* .szDefPrefix  = */ "",
+    /* .szDefSuffix  = */ ".dll",
+    /* .szLibPath    = */ ""
+};
+
+/**
+ * OS/2 'main'.
+ */
+int _System OS2Main(HMODULE hmod, ULONG ulReserved, PCH pszzEnv, PCH pszzCmdLine)
+{
+    return kLdrDyldLoadExe(&g_Args, &hmod);
+}
+
Index: /trunk/kLdr/kLdrExeStub-os2A.asm
===================================================================
--- /trunk/kLdr/kLdrExeStub-os2A.asm	(revision 2)
+++ /trunk/kLdr/kLdrExeStub-os2A.asm	(revision 2)
@@ -0,0 +1,44 @@
+; $Id$
+;; @file
+; kLdr - OS/2 Loader Stub, entry point thingy...
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; In addition to the permissions in the GNU Lesser General Public
+; License, you are granted unlimited permission to link the compiled
+; version of this file into combinations with other programs, and to
+; distribute those combinations without any restriction coming from
+; the use of this file.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA
+;
+
+
+
+segment TEXT32 public CLASS=CODE align=16 use32
+extern OS2Main
+..start:
+    jmp OS2Main
+
+segment DATA32 stack CLASS=DATA align=16 use32
+
+global WEAK$ZERO
+WEAK$ZERO EQU 0
+
Index: /trunk/kLdr/kLdrExeStub-win.c
===================================================================
--- /trunk/kLdr/kLdrExeStub-win.c	(revision 2)
+++ /trunk/kLdr/kLdrExeStub-win.c	(revision 2)
@@ -0,0 +1,64 @@
+/* $Id$ */
+/** @file
+ * kLdr - Windows Loader Stub.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include <Windows.h>
+#include "kLdrInternal.h"
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The stub arguments. */
+static const KLDREXEARGS g_Args =
+{
+    /* .fFlags       = */ KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT,
+    /* .enmSearch    = */ KLDRDYLD_SEARCH_WINDOWS,
+    /* .szExecutable = */ "tst-0", /* just while testing */
+    /* .szDefPrefix  = */ "",
+    /* .szDefSuffix  = */ "",
+    /* .szLibPath    = */ ""
+};
+
+/**
+ * Windows 'main'.
+ */
+int WindowsMain(void)
+{
+    kLdrDyldLoadExe(&g_Args, NULL);
+    /* won't happen */
+    return 0;
+}
+
Index: /trunk/kLdr/kLdrHlp.h
===================================================================
--- /trunk/kLdr/kLdrHlp.h	(revision 2)
+++ /trunk/kLdr/kLdrHlp.h	(revision 2)
@@ -0,0 +1,9 @@
+
+int     kldrHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal);
+int     kldrHlpGetEnvUZ(const char *pszVar, KSIZE *pcb);
+
+void    kldrHlpExit(int rc);
+void    kldrHlpSleep(unsigned cMillies);
+
+char   *kldrHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase);
+
Index: /trunk/kLdr/kLdrInternal.h
===================================================================
--- /trunk/kLdr/kLdrInternal.h	(revision 2)
+++ /trunk/kLdr/kLdrInternal.h	(revision 2)
@@ -0,0 +1,463 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Dynamic Loader, internal header.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef ___kLdrInternal_h___
+#define ___kLdrInternal_h___
+
+#include <k/kHlp.h>
+#include <k/kRdr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(__X86__) && !defined(__AMD64__)
+# if defined(__i386__) || defined(_M_IX86)
+#  define __X86__
+# elif defined(__x86_64__) || defined(_M_X64) || defined(__AMD64__) || defined(_M_AMD64)
+#  define __AMD64__
+# else
+#  error "can't figure out the target arch."
+# endif
+#endif
+
+/* ignore definitions in winnt.h */
+#undef IMAGE_DOS_SIGNATURE
+#undef IMAGE_NT_SIGNATURE
+
+/** @name Signatures we know
+ * @{ */
+/** ELF signature ("\x7fELF"). */
+#define IMAGE_ELF_SIGNATURE         K_LE2H_U32(0x7f | ('E' << 8) | ((KU32)'L' << 16) | ((KU32)'F' << 24))
+/** PE signature ("PE\0\0"). */
+#define IMAGE_NT_SIGNATURE          K_LE2H_U32('P' | ('E' << 8))
+/** LX signature ("LX") */
+#define IMAGE_LX_SIGNATURE          K_LE2H_U16('L' | ('X' << 8))
+/** LE signature ("LE") */
+#define IMAGE_LE_SIGNATURE          K_LE2H_U16('L' | ('E' << 8))
+/** NE signature ("NE") */
+#define IMAGE_NE_SIGNATURE          K_LE2H_U16('N' | ('E' << 8))
+/** MZ signature ("MZ"). */
+#define IMAGE_DOS_SIGNATURE         K_LE2H_U16('M' | ('Z' << 8))
+/** The FAT signature (universal binaries). */
+#define IMAGE_FAT_SIGNATURE         KU32_C(0xcafebabe)
+/** The FAT signature (universal binaries), other endian. */
+#define IMAGE_FAT_SIGNATURE_OE      KU32_C(0xbebafeca)
+/** The 32-bit Mach-O signature. */
+#define IMAGE_MACHO32_SIGNATURE     KU32_C(0xfeedface)
+/** The 32-bit Mach-O signature, other endian. */
+#define IMAGE_MACHO32_SIGNATURE_OE  KU32_C(0xcefaedfe)
+/** The 64-bit Mach-O signature. */
+#define IMAGE_MACHO64_SIGNATURE     KU32_C(0xfeedfacf)
+/** The 64-bit Mach-O signature, other endian. */
+#define IMAGE_MACHO64_SIGNATURE_OE  KU32_C(0xfefaedfe)
+/** @} */
+
+/** @defgroup grp_kLdrInternal  Internals
+ * @internal
+ * @{
+ */
+
+
+/**
+ * The state of a dynamic loader module.
+ * @image html KLDRSTATE.gif "The state diagram"
+ */
+typedef enum KLDRSTATE
+{
+    /** The usual invalid 0 enum. */
+    KLDRSTATE_INVALID = 0,
+
+    /** The module has just been opened and linked into the load list.
+     *
+     * Prev state: -
+     * Next state: MAPPED, PENDING_DESTROY
+     */
+    KLDRSTATE_OPEN,
+
+    /** The module segments has been mapped into the process memory.
+     *
+     * Prev state: OPEN
+     * Next state: LOADED_PREREQUISITES, PENDING_DESTROY
+     */
+    KLDRSTATE_MAPPED,
+    /** The module has been reloaded and needs to be fixed up again.
+     * This can occure when the loader is called recursivly.
+     *
+     * The reason RELOADED modules must go back to the PENDING_GC state is
+     * because we want to guard against uninit order issues, and therefore
+     * doesn't unmap modules untill all pending termintation callbacks has
+     * been executed.
+     *
+     * Prev state: PENDING_GC
+     * Next state: RELOADED_LOADED_PREREQUISITES, PENDING_GC
+     */
+    KLDRSTATE_RELOADED,
+
+    /** The immediate prerequisites have been loaded.
+     *
+     * Prev state: MAPPED
+     * Next state: FIXED_UP, PENDING_DESTROY
+     */
+    KLDRSTATE_LOADED_PREREQUISITES,
+    /** The immediate prerequisites have been loaded for a reloaded module.
+     *
+     * Prev state: RELOADED
+     * Next state: RELOADED_FIXED_UP, PENDING_GC
+     */
+    KLDRSTATE_RELOADED_LOADED_PREREQUISITES,
+
+    /** Fixups has been applied.
+     *
+     * Prev state: LOADED_PREREQUISITES
+     * Next state: PENDING_INITIALIZATION, PENDING_DESTROY
+     */
+    KLDRSTATE_FIXED_UP,
+    /** Fixups has been applied.
+     *
+     * Prev state: RELOADED_LOADED_PREREQUISITES
+     * Next state: PENDING_INITIALIZATION, PENDING_GC
+     */
+    KLDRSTATE_RELOADED_FIXED_UP,
+
+    /** Pending initialization.
+     * While the module is in this state the loader is in reentrant mode.
+     *
+     * Prev state: FIXED_UP, RELOADED_FIXED_UP
+     * Next state: INITIALIZATION, PENDING_GC
+     */
+    KLDRSTATE_PENDING_INITIALIZATION,
+
+    /** Initializing.
+     * While the module is in this state the loader is in reentrant mode.
+     *
+     * Prev state: PENDING_INITIALIZATION
+     * Next state: GOOD, PENDING_GC
+     */
+    KLDRSTATE_INITIALIZING,
+
+    /** Initialization failed.
+     *
+     * This is somewhat similar to PENDING_GC except that, a module
+     * in this state cannot be reloaded untill we've done GC. This ensures
+     * that a init failure during recursive loading is propagated up.
+     *
+     * While the module is in this state the loader is in reentrant mode.
+     *
+     * Prev state: INITIALIZING
+     * Next state: GC
+     */
+    KLDRSTATE_INITIALIZATION_FAILED,
+
+    /** The module has been successfully loaded and initialized.
+     * While the module is in this state the loader can be in reentrant
+     * or 'unused' mode.
+     *
+     * Prev state: INITIALIZING
+     * Next state: PENDING_TERMINATION
+     */
+    KLDRSTATE_GOOD,
+
+    /** Pending termination, reference count is 0.
+     * While the module is in this state the loader is in reentrant mode.
+     * Prerequisite modules are dropped when a module enters this state.
+     *
+     * Prev state: GOOD
+     * Next state: TERMINATING, GOOD
+     */
+    KLDRSTATE_PENDING_TERMINATION,
+
+    /** Terminating, reference count is still 0.
+     * While the module is in this state the loader is in reentrant mode.
+     *
+     * Prev state: PENDING_TERMINATION
+     * Next state: PENDING_GC
+     */
+    KLDRSTATE_TERMINATING,
+
+    /** Pending garbage collection.
+     * Prerequisite modules are dropped when a module enters this state (if not done already).
+     *
+     * Prev state: TERMINATING, PENDING_INITIALIZATION, INITIALIZATION_FAILED
+     * Next state: GC, RELOADED
+     */
+    KLDRSTATE_PENDING_GC,
+
+    /** Being garbage collected.
+     *
+     * Prev state: PENDING_GC, INITIALIZATION_FAILED
+     * Next state: PENDING_DESTROY, DESTROYED
+     */
+    KLDRSTATE_GC,
+
+    /** The module has be unlinked, but there are still stack references to it.
+     *
+     * Prev state: GC, FIXED_UP, LOADED_PREREQUISITES, MAPPED, OPEN
+     * Next state: DESTROYED
+     */
+    KLDRSTATE_PENDING_DESTROY,
+
+    /** The module has been destroyed but not freed yet.
+     *
+     * This happens when a module ends up being destroyed when cRefs > 0. The
+     * module structure will be freed when cRefs reaches 0.
+     *
+     * Prev state: GC, PENDING_DESTROY
+     */
+    KLDRSTATE_DESTROYED,
+
+    /** The end of valid states (exclusive) */
+    KLDRSTATE_END = KLDRSTATE_DESTROYED,
+    /** The usual 32-bit blowup. */
+    KLDRSTATE_32BIT_HACK = 0x7fffffff
+} KLDRSTATE;
+
+
+/**
+ * Dynamic loader module.
+ */
+typedef struct KLDRDYLDMOD
+{
+    /** Magic number. */
+    KU32                u32MagicHead;
+    /** The module state. */
+    KLDRSTATE           enmState;
+    /** The module. */
+    PKLDRMOD            pMod;
+    /** The module handle. */
+    HKLDRMOD            hMod;
+    /** The total number of references. */
+    KU32                cRefs;
+    /** The number of dependency references. */
+    KU32                cDepRefs;
+    /** The number of dynamic load references. */
+    KU32                cDynRefs;
+    /** Set if this is the executable module.
+     * When clear, the module is a shared object or relocatable object. */
+    KU32                fExecutable : 1;
+    /** Global DLL (set) or specific DLL (clear). */
+    KU32                fGlobalOrSpecific : 1;
+    /** Whether the module contains bindable symbols in the global unix namespace. */
+    KU32                fBindable : 1;
+    /** Set if linked into the global init list. */
+    KU32                fInitList : 1;
+    /** Already loaded or checked prerequisites.
+     * This flag is used when loading prerequisites, when set it means that
+     * this module is already seen and shouldn't be processed again. */
+    KU32                fAlreadySeen : 1;
+    /** Set if the module is currently mapped.
+     * This is used to avoid unnecessary calls to kLdrModUnmap during cleanup. */
+    KU32                fMapped : 1;
+    /** Set if TLS allocation has been done. (part of the mapping). */
+    KU32                fAllocatedTLS : 1;
+    /** Reserved for future use. */
+    KU32                f25Reserved : 25;
+    /** The load list linkage. */
+    struct
+    {
+        /** The next module in the list. */
+        struct KLDRDYLDMOD *pNext;
+        /** The prev module in the list. */
+        struct KLDRDYLDMOD *pPrev;
+    } Load;
+    /** The initialization and termination list linkage.
+     * If non-recursive initialization is used, the module will be pushed on
+     * the initialization list.
+     * A module will be linked into the termination list upon a successful
+     * return from module initialization. */
+    struct
+    {
+        /** The next module in the list. */
+        struct KLDRDYLDMOD *pNext;
+        /** The prev module in the list. */
+        struct KLDRDYLDMOD *pPrev;
+    } InitTerm;
+    /** The bind order list linkage.
+     * The module is not in this list when fBindable is clear. */
+    struct
+    {
+        /** The next module in the list. */
+        struct KLDRDYLDMOD *pNext;
+        /** The prev module in the list. */
+        struct KLDRDYLDMOD *pPrev;
+    } Bind;
+
+    /** The number of prerequisite modules in the prereq array. */
+    KU32                cPrereqs;
+    /** Pointer to an array of prerequisite module pointers.
+     * This array is only filled when in the states starting with
+     * KLDRSTATE_LOADED_PREREQUISITES thru KLDRSTATE_GOOD.
+     */
+    struct KLDRDYLDMOD **papPrereqs;
+
+    /** Magic number. */
+    KU32                u32MagicTail;
+} KLDRDYLDMOD, *PKLDRDYLDMOD, **PPKLDRDYLDMOD;
+
+/** KLDRDYLDMOD magic value. (Fuyumi Soryo) */
+#define KLDRDYMOD_MAGIC     0x19590106
+
+/** Return / crash validation of a module handle argument. */
+#define KLDRDYLD_VALIDATE_HKLDRMOD(hMod) \
+    do  { \
+        if (    (hMod) == NIL_HKLDRMOD \
+            ||  (hMod)->u32MagicHead != KLDRDYMOD_MAGIC \
+            ||  (hMod)->u32MagicTail != KLDRDYMOD_MAGIC) \
+        { \
+            return KERR_INVALID_HANDLE; \
+        } \
+    } while (0)
+
+
+int kldrInit(void);
+void kldrTerm(void);
+
+int kldrDyldInit(void);
+void kldrDyldTerm(void);
+
+void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe);
+int kldrDyldFailure(int rc, const char *pszFormat, ...);
+
+int kldrDyldOSStartExe(KUPTR uMainEntrypoint, void *pvStack, KSIZE cbStack);
+void *kldrDyldOSAllocStack(KSIZE cb);
+
+int kldrDyldFindInit(void);
+int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
+                          KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod);
+int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
+                               KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod);
+
+int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch,
+                            unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod);
+
+
+int kldrDyldModCreate(PKRDR pRdr, KU32 fFlags, PPKLDRDYLDMOD ppMod);
+void kldrDyldModDestroy(PKLDRDYLDMOD pMod);
+void kldrDyldModAddRef(PKLDRDYLDMOD pMod);
+void kldrDyldModDeref(PKLDRDYLDMOD pMod);
+void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep);
+void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep);
+int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod);
+int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod);
+void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod);
+void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod);
+void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep);
+void kldrDyldModClearBindable(PKLDRDYLDMOD pMod);
+int kldrDyldModMap(PKLDRDYLDMOD pMod);
+int kldrDyldModUnmap(PKLDRDYLDMOD pMod);
+int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix,
+                                 KLDRDYLDSEARCH enmSearch, unsigned fFlags);
+int kldrDyldModCheckPrerequisites(PKLDRDYLDMOD pMod);
+void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod);
+int kldrDyldModFixup(PKLDRDYLDMOD pMod);
+int kldrDyldModCallInit(PKLDRDYLDMOD pMod);
+void kldrDyldModCallTerm(PKLDRDYLDMOD pMod);
+int kldrDyldModReload(PKLDRDYLDMOD pMod);
+int kldrDyldModAttachThread(PKLDRDYLDMOD pMod);
+void kldrDyldModDetachThread(PKLDRDYLDMOD pMod);
+int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, KSIZE *pcbStack);
+int kldrDyldModStartExe(PKLDRDYLDMOD pMod);
+
+int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName);
+int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename);
+int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *puValue, KU32 *pfKind);
+
+
+/** Pointer to the head module (the executable).
+ * (This is exported, so no prefix.) */
+extern PKLDRDYLDMOD     kLdrDyldHead;
+/** Pointer to the tail module.
+ * (This is exported, so no prefix.) */
+extern PKLDRDYLDMOD     kLdrDyldTail;
+/** Pointer to the head module of the initialization list.
+ * The outermost load call will pop elements from this list in LIFO order (i.e.
+ * from the tail). The list is only used during non-recursive initialization
+ * and may therefore share the pNext/pPrev members with the termination list
+ * since we don't push a module onto the termination list untill it has been
+ * successfully initialized. */
+extern PKLDRDYLDMOD     g_pkLdrDyldInitHead;
+/** Pointer to the tail module of the initalization list. */
+extern PKLDRDYLDMOD     g_pkLdrDyldInitTail;
+/** Pointer to the head module of the termination order list. */
+extern PKLDRDYLDMOD     g_pkLdrDyldTermHead;
+/** Pointer to the tail module of the termination order list. */
+extern PKLDRDYLDMOD     g_pkLdrDyldTermTail;
+/** Pointer to the head module of the bind order list.
+ * The modules in this list makes up the global namespace used when binding symbol unix fashion. */
+extern PKLDRDYLDMOD     g_pkLdrDyldBindHead;
+/** Pointer to the tail module of the bind order list. */
+extern PKLDRDYLDMOD     g_pkLdrDyldBindTail;
+
+/** Indicates that the other MainStack globals have been filled in. */
+extern unsigned         g_fkLdrDyldDoneMainStack;
+/** Whether the stack was allocated seperatly or was part of the executable. */
+extern unsigned         g_fkLdrDyldMainStackAllocated;
+/** Pointer to the main stack object. */
+extern void            *g_pvkLdrDyldMainStack;
+/** The size of the main stack object. */
+extern KSIZE            g_cbkLdrDyldMainStack;
+
+/** The global error buffer. */
+extern char             g_szkLdrDyldError[1024];
+
+extern char             kLdrDyldExePath[8192];
+extern char             kLdrDyldLibraryPath[8192];
+extern char             kLdrDyldDefPrefix[16];
+extern char             kLdrDyldDefSuffix[16];
+
+extern int              g_fBootstrapping;
+
+
+/** @name The Loader semaphore
+ * @{ */
+int     kLdrDyldSemInit(void);
+void    kLdrDyldSemTerm(void);
+int     kLdrDyldSemRequest(void);
+void    kLdrDyldSemRelease(void);
+/** @} */
+
+
+/** @name Module interpreter method tables
+ * @{ */
+extern KLDRMODOPS       g_kLdrModLXOps;
+extern KLDRMODOPS       g_kLdrModMachOOps;
+extern KLDRMODOPS       g_kLdrModNativeOps;
+extern KLDRMODOPS       g_kLdrModPEOps;
+/** @} */
+
+
+/** @} */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /trunk/kLdr/kLdrMod.c
===================================================================
--- /trunk/kLdr/kLdrMod.c	(revision 2)
+++ /trunk/kLdr/kLdrMod.c	(revision 2)
@@ -0,0 +1,717 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Module Interpreter.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+#include <k/kCpu.h>
+#include <k/kLdrFmts/mz.h>
+#if 1 /* testing headers */
+# include <k/kLdrFmts/pe.h>
+# include <k/kLdrFmts/lx.h>
+# include <k/kLdrFmts/elf32.h>
+# include <k/kLdrFmts/elf64.h>
+# include <k/kLdrFmts/mach-o.h>
+#endif
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRMOD_STRICT
+ * Define KLDRMOD_STRICT to enabled strict checks in KLDRMOD. */
+#define KLDRMOD_STRICT 1
+
+/** @def KLDRMOD_ASSERT
+ * Assert that an expression is true when KLDR_STRICT is defined.
+ */
+#ifdef KLDRMOD_STRICT
+# define KLDRMOD_ASSERT(expr)  kHlpAssert(expr)
+#else
+# define KLDRMOD_ASSERT(expr)  do {} while (0)
+#endif
+
+/** Return / crash validation of a module argument. */
+#define KLDRMOD_VALIDATE_EX(pMod, rc) \
+    do  { \
+        if (    (pMod)->u32Magic != KLDRMOD_MAGIC \
+            ||  (pMod)->pOps == NULL \
+           )\
+        { \
+            return (rc); \
+        } \
+    } while (0)
+
+/** Return / crash validation of a module argument. */
+#define KLDRMOD_VALIDATE(pMod) \
+    KLDRMOD_VALIDATE_EX(pMod, KERR_INVALID_PARAMETER)
+
+/** Return / crash validation of a module argument. */
+#define KLDRMOD_VALIDATE_VOID(pMod) \
+    do  { \
+        if (    (pMod)->u32Magic != KLDRMOD_MAGIC \
+            ||  (pMod)->pOps == NULL \
+           )\
+        { \
+            return; \
+        } \
+    } while (0)
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The list of module interpreters. */
+static PCKLDRMODOPS g_pModInterpreterHead = NULL;
+
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+
+
+
+/**
+ * Open a executable image by file name.
+ *
+ * @returns 0 on success and *ppMod pointing to a module instance.
+ *          On failure, a non-zero OS specific error code is returned.
+ * @param   pszFilename     The filename to open.
+ * @param   ppMod           Where to store the module handle.
+ */
+int kLdrModOpen(const char *pszFilename, PPKLDRMOD ppMod)
+{
+    /*
+     * Open the file using a bit provider.
+     */
+    PKRDR pRdr;
+    int rc = kRdrOpen(&pRdr, pszFilename);
+    if (!rc)
+    {
+        rc = kLdrModOpenFromRdr(pRdr, ppMod);
+        if (!rc)
+            return 0;
+       kRdrClose(pRdr);
+    }
+    return rc;
+}
+
+
+/**
+ * Open a executable image from a file provider instance.
+ *
+ * @returns 0 on success and *ppMod pointing to a module instance.
+ *          On failure, a non-zero OS specific error code is returned.
+ * @param   pRdr            The file provider instance to use.
+ *                          On success, the ownership of the instance is taken by the
+ *                          module and the caller must not ever touch it again.
+ *                          (The instance is not closed on failure, the call has to do that.)
+ * @param   ppMod           Where to store the module handle.
+ */
+int kLdrModOpenFromRdr(PKRDR pRdr, PPKLDRMOD ppMod)
+{
+    union
+    {
+        KU32        u32;
+        KU16        u16;
+        KU16        au16[2];
+        KU8         au8[4];
+    }           u;
+    KLDRFOFF    offHdr = 0;
+    int         rc;
+
+    /*
+     * Try figure out what kind of image this is.
+     * Always read the 'new header' if we encounter MZ.
+     */
+    rc = kRdrRead(pRdr, &u, sizeof(u), 0);
+    if (rc)
+        return rc;
+    if (    u.u16 == IMAGE_DOS_SIGNATURE
+        &&  kRdrSize(pRdr) > sizeof(IMAGE_DOS_HEADER))
+    {
+        rc = kRdrRead(pRdr, &u, sizeof(u.u32), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew));
+        if (rc)
+            return rc;
+        if ((KLDRFOFF)u.u32 < kRdrSize(pRdr))
+        {
+            offHdr = u.u32;
+            rc = kRdrRead(pRdr, &u, sizeof(u.u32), offHdr);
+            if (rc)
+                return rc;
+        }
+        else
+            u.u16 = IMAGE_DOS_SIGNATURE;
+    }
+
+    /*
+     * Use the magic to select the appropriate image interpreter head on.
+     */
+    if (u.u16 == IMAGE_DOS_SIGNATURE)
+        rc = KLDR_ERR_MZ_NOT_SUPPORTED;
+    else if (u.u16 == IMAGE_NE_SIGNATURE)
+        rc = KLDR_ERR_NE_NOT_SUPPORTED;
+    else if (u.u16 == IMAGE_LX_SIGNATURE)
+        rc = g_kLdrModLXOps.pfnCreate(&g_kLdrModLXOps, pRdr, offHdr, ppMod);
+    else if (u.u16 == IMAGE_LE_SIGNATURE)
+        rc = KLDR_ERR_LE_NOT_SUPPORTED;
+    else if (u.u32 == IMAGE_NT_SIGNATURE)
+        rc = g_kLdrModPEOps.pfnCreate(&g_kLdrModPEOps, pRdr, offHdr, ppMod);
+    else if (   u.u32 == IMAGE_MACHO32_SIGNATURE
+             || u.u32 == IMAGE_MACHO32_SIGNATURE_OE
+             || u.u32 == IMAGE_MACHO64_SIGNATURE
+             || u.u32 == IMAGE_MACHO64_SIGNATURE_OE)
+        rc = g_kLdrModMachOOps.pfnCreate(&g_kLdrModMachOOps, pRdr, offHdr, ppMod);
+    else if (u.u32 == IMAGE_ELF_SIGNATURE)
+        rc = KLDR_ERR_ELF_NOT_SUPPORTED;
+    else if (   u.u32 == IMAGE_FAT_SIGNATURE
+             || u.u32 == IMAGE_FAT_SIGNATURE_OE)
+        rc = KLDR_ERR_FAT_NOT_SUPPORTED;
+    else
+        rc = KLDR_ERR_UNKNOWN_FORMAT;
+
+    /*
+     * If no head on hit, let each interpreter have a go.
+     */
+    if (rc)
+    {
+        PCKLDRMODOPS pOps;
+        for (pOps = g_pModInterpreterHead; pOps; pOps = pOps->pNext)
+        {
+            int rc2 = pOps->pfnCreate(pOps, pRdr, offHdr, ppMod);
+            if (!rc2)
+                return rc;
+        }
+        *ppMod = NULL;
+    }
+    return rc;
+}
+
+
+/**
+ * Closes an open module.
+ *
+ * The caller is responsible for calling kLdrModUnmap() and kLdrFreeTLS()
+ * before closing the module.
+ *
+ * @returns 0 on success, non-zero on failure. The module instance state
+ *          is unknown on failure, it's best not to touch it.
+ * @param   pMod    The module.
+ */
+int     kLdrModClose(PKLDRMOD pMod)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnDestroy(pMod);
+}
+
+
+/**
+ * Queries a symbol by name or ordinal number.
+ *
+ * @returns 0 and *puValue and *pfKind on success.
+ *          KLDR_ERR_SYMBOL_NOT_FOUND is returned if the symbol wasn't found.
+ *          Other failures could stem from bad executable format failures,
+ *          read failure in case pvBits isn't specified and no mapping should be used.
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ * @param   BaseAddress     The module base address to use when calculating the symbol value.
+ *                          There are two special values that can be used:
+ *                              KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
+ * @param   iSymbol         The symbol ordinal. (optional)
+ * @param   pchSymbol       The symbol name. (optional)
+ *                          Important, this doesn't have to be a null-terminated string.
+ * @param   cchSymbol       The length of the symbol name.
+ * @param   pszVersion      The symbol version. NULL if not versioned.
+ * @param   pfnGetForwarder The callback to use when resolving a forwarder symbol. This is optional
+ *                          and if not specified KLDR_ERR_FORWARDER is returned instead.
+ * @param   pvUser          The user argument for the pfnGetForwarder callback.
+ * @param   puValue         Where to store the symbol value. (optional)
+ * @param   pfKind          On input one of the KLDRSYMKIND_REQ_* #defines.
+ *                          On output the symbol kind. (optional)
+ */
+int     kLdrModQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
+                           const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                           PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
+{
+    KLDRMOD_VALIDATE(pMod);
+    if (!puValue && !pfKind)
+        return KERR_INVALID_PARAMETER;
+    if (puValue)
+        *puValue = 0;
+    if (pfKind)
+        K_VALIDATE_FLAGS(*pfKind, KLDRSYMKIND_REQ_SEGMENTED);
+    return pMod->pOps->pfnQuerySymbol(pMod, pvBits, BaseAddress, iSymbol, pchSymbol, cchSymbol, pszVersion,
+                                      pfnGetForwarder, pvUser, puValue, pfKind);
+}
+
+
+/**
+ * Enumerate the symbols in the module.
+ *
+ * @returns 0 on success and non-zero a status code on failure.
+ * @param   pMod            The module which symbols should be enumerated.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ * @param   BaseAddress     The module base address to use when calculating the symbol values.
+ *                          There are two special values that could be can:
+ *                              KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
+ * @param   fFlags          The enumeration flags. A combination of the KLDRMOD_ENUM_SYMS_FLAGS_* \#defines.
+ * @param   pfnCallback     The enumeration callback function.
+ * @param   pvUser          The user argument to the callback function.
+ */
+int     kLdrModEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags,
+                           PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
+{
+    KLDRMOD_VALIDATE(pMod);
+    K_VALIDATE_FLAGS(fFlags, KLDRMOD_ENUM_SYMS_FLAGS_ALL);
+    return pMod->pOps->pfnEnumSymbols(pMod, pvBits, BaseAddress, fFlags, pfnCallback, pvUser);
+}
+
+
+/**
+ * Get the name of an import module by ordinal number.
+ *
+ * @returns 0 and name in pszName on success.
+ *          On buffer overruns KERR_BUFFER_OVERFLOW will be returned.
+ *          On other failures and appropriate error code is returned.
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits().
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ * @param   iImport         The import module ordinal number.
+ * @param   pszName         Where to store the name.
+ * @param   cchName         The size of the name buffer.
+ */
+int     kLdrModGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnGetImport(pMod, pvBits, iImport, pszName, cchName);
+}
+
+
+/**
+ * Get the number of import modules.
+ *
+ * @returns The number of import modules. -1 if something really bad happens.
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits().
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ */
+KI32 kLdrModNumberOfImports(PKLDRMOD pMod, const void *pvBits)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnNumberOfImports(pMod, pvBits);
+}
+
+
+/**
+ * Checks if this module can be executed by the specified arch+cpu.
+ *
+ * @returns 0 if it can, KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE if it can't.
+ *          Other failures may occur and cause other return values.
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits().
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ */
+int     kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu)
+{
+    KLDRMOD_VALIDATE(pMod);
+    if (pMod->pOps->pfnCanExecuteOn)
+        return pMod->pOps->pfnCanExecuteOn(pMod, pvBits, enmArch, enmCpu);
+    return kCpuCompare(pMod->enmArch, pMod->enmCpu, enmArch, enmCpu);
+}
+
+
+/**
+ * Gets the image stack info.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   pMod
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ * @param   BaseAddress     The module base address to use when calculating the stack address.
+ *                          There are two special values that can be used:
+ *                              KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
+ * @param   pStackInfo      The stack information.
+ */
+int     kLdrModGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnGetStackInfo(pMod, pvBits, BaseAddress, pStackInfo);
+}
+
+
+/**
+ * Queries the main entrypoint of the module.
+ *
+ * Only executable are supposed to have an main entrypoint, though some object and DLL
+ * formats will also allow this.
+ *
+ * @returns 0 and *pMainEPAddress on success. Non-zero status code on failure.
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ * @param   BaseAddress     The module base address to use when calculating the entrypoint address.
+ *                          There are two special values that can be used:
+ *                              KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
+ * @param   pMainEPAddress  Where to store the entry point address.
+ */
+int     kLdrModQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
+{
+    KLDRMOD_VALIDATE(pMod);
+    *pMainEPAddress = 0;
+    return pMod->pOps->pfnQueryMainEntrypoint(pMod, pvBits, BaseAddress, pMainEPAddress);
+}
+
+
+/**
+ * Queries info about a resource.
+ *
+ * If there are multiple resources matching the criteria, the best or
+ * first match will be return.
+ *
+ *
+ * @returns 0 on success.
+ * @returns Whatever non-zero status returned by pfnCallback (enumeration was stopped).
+ * @returns non-zero kLdr or native status code on failure.
+ *
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ * @param   BaseAddress     The module base address to use when calculating the resource addresses.
+ *                          There are two special values that can be used:
+ *                              KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
+ * @param   idType          The resource type id to match if not NIL_KLDRMOD_RSRC_TYPE_ID.
+ * @param   pszType         The resource type name to match if no NULL.
+ * @param   idName          The resource name id to match if not NIL_KLDRMOD_RSRC_NAME_ID.
+ * @param   pszName         The resource name to match if not NULL.
+ * @param   idLang          The language id to match.
+ * @param   pfnCallback     The callback function.
+ * @param   pvUser          The user argument for the callback.
+ */
+int     kLdrModQueryResource(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType,
+                             KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc)
+{
+    KLDRMOD_VALIDATE(pMod);
+    if (!pAddrRsrc && !pcbRsrc)
+        return KERR_INVALID_PARAMETER;
+    if (pAddrRsrc)
+        *pAddrRsrc = NIL_KLDRADDR;
+    if (pcbRsrc)
+        *pcbRsrc = 0;
+    return pMod->pOps->pfnQueryResource(pMod, pvBits, BaseAddress, idType, pszType, idName, pszName, idLang, pAddrRsrc, pcbRsrc);
+}
+
+
+/**
+ * Enumerates the resources matching the specfied criteria.
+ *
+ *
+ * @returns 0 on success.
+ * @returns Whatever non-zero status returned by pfnCallback (enumeration was stopped).
+ * @returns non-zero kLdr or native status code on failure.
+ *
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress.
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ * @param   BaseAddress     The module base address to use when calculating the resource addresses.
+ *                          There are two special values that can be used:
+ *                              KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP.
+ * @param   idType          The resource type id to match if not NIL_KLDRMOD_RSRC_TYPE_ID.
+ * @param   pszType         The resource type name to match if no NULL.
+ * @param   idName          The resource name id to match if not NIL_KLDRMOD_RSRC_NAME_ID.
+ * @param   pszName         The resource name to match if not NULL.
+ * @param   idLang          The language id to match.
+ * @param   pfnCallback     The callback function.
+ * @param   pvUser          The user argument for the callback.
+ */
+int     kLdrModEnumResources(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType,
+                             KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnEnumResources(pMod, pvBits, BaseAddress, idType, pszType, idName, pszName, idLang, pfnCallback, pvUser);
+}
+
+
+/**
+ * Enumerate the debug info formats contained in the executable image.
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure, or non-zero callback status.
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits().
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ * @param   pfnCallback     The callback function.
+ * @param   pvUser          The user argument.
+ * @see pg_kDbg for the debug info reader.
+ */
+int     kLdrModEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnEnumDbgInfo(pMod, pvBits, pfnCallback, pvUser);
+}
+
+
+/**
+ * Checks if the module has debug info embedded or otherwise associated with it.
+ *
+ * @returns 0 if it has debug info, KLDR_ERR_NO_DEBUG_INFO if no debug info,
+ *          and non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module.
+ * @param   pvBits          Optional pointer to bits returned by kLdrModGetBits().
+ *                          This can be used by some module interpreters to reduce memory consumption.
+ */
+int     kLdrModHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnHasDbgInfo(pMod, pvBits);
+}
+
+
+/**
+ * May free up some resources held by the module.
+ *
+ * @todo define exactly what it possible to do after this call.
+ *
+ * @returns 0 on success, KLDR_ERR_* on failure.
+ * @param   pMod    The module.
+ */
+int     kLdrModMostlyDone(PKLDRMOD pMod)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnMostlyDone(pMod);
+}
+
+
+/**
+ * Maps the module into the memory of the caller.
+ *
+ * On success the actual addresses for the segments can be found in MapAddress
+ * member of each segment in the segment array.
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module to be mapped.
+ * @remark  kLdr only supports one mapping at a time of a module.
+ */
+int     kLdrModMap(PKLDRMOD pMod)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnMap(pMod);
+}
+
+
+/**
+ * Unmaps a module previously mapped by kLdrModMap().
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module to unmap.
+ */
+int     kLdrModUnmap(PKLDRMOD pMod)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnUnmap(pMod);
+}
+
+
+/**
+ * Allocates Thread Local Storage for module mapped by kLdrModMap().
+ *
+ * Calling kLdrModAllocTLS() more than once without calling kLdrModFreeTLS()
+ * between each invocation is not supported.
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module.
+ */
+int     kLdrModAllocTLS(PKLDRMOD pMod)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnAllocTLS(pMod);
+}
+
+
+/**
+ * Frees Thread Local Storage previously allocated by kLdrModAllocTLS().
+ *
+ * The caller is responsible for only calling kLdrModFreeTLS() once
+ * after calling kLdrModAllocTLS().
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module.
+ */
+void    kLdrModFreeTLS(PKLDRMOD pMod)
+{
+    KLDRMOD_VALIDATE_VOID(pMod);
+    pMod->pOps->pfnFreeTLS(pMod);
+}
+
+
+/**
+ * Reloads all dirty pages in a module previously mapped by kLdrModMap().
+ *
+ * The module interpreter may omit code pages if it can safely apply code
+ * fixups again in a subsequent kLdrModFixupMapping() call.
+ *
+ * The caller is responsible for freeing TLS before calling this function.
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module.
+ */
+int     kLdrModReload(PKLDRMOD pMod)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnReload(pMod);
+}
+
+
+/**
+ * Fixup the mapping made by kLdrModMap().
+ *
+ * The caller is only responsible for not calling this function more than
+ * once without doing kLDrModReload() inbetween.
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module.
+ * @param   pfnGetImport    The callback for resolving external (imported) symbols.
+ * @param   pvUser          The callback user argument.
+ */
+int     kLdrModFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnFixupMapping(pMod, pfnGetImport, pvUser);
+}
+
+
+/**
+ * Call the module initializiation function of a mapped module (if any).
+ *
+ * @returns 0 on success or no init function, non-zero on init function failure or invalid pMod.
+ * @param   pMod            The module.
+ * @param   uHandle         The module handle to use if any of the init functions requires the module handle.
+ */
+int     kLdrModCallInit(PKLDRMOD pMod, KUPTR uHandle)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnCallInit(pMod, uHandle);
+}
+
+
+/**
+ * Call the module termination function of a mapped module (if any).
+ *
+ * @returns 0 on success or no term function, non-zero on invalid pMod.
+ * @param   pMod            The module.
+ * @param   uHandle         The module handle to use if any of the term functions requires the module handle.
+ *
+ * @remark  Termination function failure will be ignored by the module interpreter.
+ */
+int     kLdrModCallTerm(PKLDRMOD pMod, KUPTR uHandle)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnCallTerm(pMod, uHandle);
+}
+
+
+/**
+ * Call the thread attach or detach function of a mapped module (if any).
+ *
+ * Any per-thread TLS initialization/termination will have to be done at this time too.
+ *
+ * @returns 0 on success or no attach/detach function, non-zero on attach failure or invalid pMod.
+ * @param   pMod            The module.
+ * @param   uHandle         The module handle to use if any of the thread attach/detach functions
+ *                          requires the module handle.
+ *
+ * @remark  Detach function failure will be ignored by the module interpreter.
+ */
+int     kLdrModCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
+{
+    KLDRMOD_VALIDATE(pMod);
+    K_VALIDATE_FLAGS(fAttachingOrDetaching, 1);
+    return pMod->pOps->pfnCallThread(pMod, uHandle, fAttachingOrDetaching);
+}
+
+
+/**
+ * Get the size of the mapped module.
+ *
+ * @returns The size of the mapped module (in bytes).
+ * @param   pMod            The module.
+ */
+KLDRADDR kLdrModSize(PKLDRMOD pMod)
+{
+    KLDRMOD_VALIDATE_EX(pMod, 0);
+    return pMod->pOps->pfnSize(pMod);
+}
+
+
+/**
+ * Gets the module bits.
+ *
+ * The module interpreter will fill a mapping allocated by the caller with the
+ * module bits reallocated to the specified address.
+ *
+ * @returns 0 on succes, non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module.
+ * @param   pvBits          Where to put the bits.
+ * @param   BaseAddress     The base address that should correspond to the first byte in pvBits
+ *                          upon return.
+ * @param   pfnGetImport    The callback ufor resolving external (imported) symbols.
+ * @param   pvUser          The callback user argument.
+ */
+int     kLdrModGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnGetBits(pMod, pvBits, BaseAddress, pfnGetImport, pvUser);
+}
+
+
+/**
+ * Relocates the module bits previously obtained by kLdrModGetBits().
+ *
+ * @returns 0 on succes, non-zero OS or kLdr status code on failure.
+ * @param   pMod            The module.
+ * @param   pvBits          Where to put the bits.
+ * @param   NewBaseAddress  The new base address.
+ * @param   OldBaseAddress  The old base address (i.e. the one specified to kLdrModGetBits() or as
+ *                          NewBaseAddressto the previous kLdrModRelocateBits() call).
+ * @param   pfnGetImport    The callback ufor resolving external (imported) symbols.
+ * @param   pvUser          The callback user argument.
+ */
+int     kLdrModRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                            PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    KLDRMOD_VALIDATE(pMod);
+    return pMod->pOps->pfnRelocateBits(pMod, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
+}
+
Index: /trunk/kLdr/kLdrModLX.c
===================================================================
--- /trunk/kLdr/kLdrModLX.c	(revision 2)
+++ /trunk/kLdr/kLdrModLX.c	(revision 2)
@@ -0,0 +1,2645 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+#include <k/kLdrFmts/lx.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRMODLX_STRICT
+ * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */
+#define KLDRMODLX_STRICT 1
+
+/** @def KLDRMODLX_ASSERT
+ * Assert that an expression is true when KLDR_STRICT is defined.
+ */
+#ifdef KLDRMODLX_STRICT
+# define KLDRMODLX_ASSERT(expr)  kHlpAssert(expr)
+#else
+# define KLDRMODLX_ASSERT(expr)  do {} while (0)
+#endif
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Instance data for the LX module interpreter.
+ */
+typedef struct KLDRMODLX
+{
+    /** Pointer to the module. (Follows the section table.) */
+    PKLDRMOD                pMod;
+    /** Pointer to the user mapping. */
+    const void             *pvMapping;
+    /** The size of the mapped LX image. */
+    KSIZE                   cbMapped;
+    /** Reserved flags. */
+    KU32                    f32Reserved;
+
+    /** The offset of the LX header. */
+    KLDRFOFF                offHdr;
+    /** Copy of the LX header. */
+    struct e32_exe          Hdr;
+
+    /** Pointer to the loader section.
+     * Allocated together with this strcture. */
+    const KU8              *pbLoaderSection;
+    /** Pointer to the last byte in the loader section. */
+    const KU8              *pbLoaderSectionLast;
+    /** Pointer to the object table in the loader section. */
+    const struct o32_obj   *paObjs;
+    /** Pointer to the object page map table in the loader section. */
+    const struct o32_map   *paPageMappings;
+    /** Pointer to the resource table in the loader section. */
+    const struct rsrc32    *paRsrcs;
+    /** Pointer to the resident name table in the loader section. */
+    const KU8              *pbResNameTab;
+    /** Pointer to the entry table in the loader section. */
+    const KU8              *pbEntryTab;
+
+    /** Pointer to the non-resident name table. */
+    KU8                    *pbNonResNameTab;
+    /** Pointer to the last byte in the non-resident name table. */
+    const KU8              *pbNonResNameTabLast;
+
+    /** Pointer to the fixup section. */
+    KU8                    *pbFixupSection;
+    /** Pointer to the last byte in the fixup section. */
+    const KU8              *pbFixupSectionLast;
+    /** Pointer to the fixup page table within pvFixupSection. */
+    const KU32             *paoffPageFixups;
+    /** Pointer to the fixup record table within pvFixupSection. */
+    const KU8              *pbFixupRecs;
+    /** Pointer to the import module name table within pvFixupSection. */
+    const KU8              *pbImportMods;
+    /** Pointer to the import module name table within pvFixupSection. */
+    const KU8              *pbImportProcs;
+} KLDRMODLX, *PKLDRMODLX;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits);
+static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                                 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX);
+static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KI32 cbNameTable, KU32 iOrdinal);
+static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KU32 cchSymbol, KU32 *piSymbol);
+static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KI32 cbNameTable,
+                                                       const char *pchSymbol, KSIZE cchSymbol);
+static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
+static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc);
+static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc);
+static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb);
+static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
+static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, KUPTR uHandle);
+static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
+                                     PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind);
+static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX);
+static KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved);
+static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc,
+                            int iSelector, KLDRADDR uValue, KU32 fKind);
+
+
+/**
+ * Create a loader module instance interpreting the executable image found
+ * in the specified file provider instance.
+ *
+ * @returns 0 on success and *ppMod pointing to a module instance.
+ *          On failure, a non-zero OS specific error code is returned.
+ * @param   pOps            Pointer to the registered method table.
+ * @param   pRdr            The file provider instance to use.
+ * @param   offNewHdr       The offset of the new header in MZ files. -1 if not found.
+ * @param   ppMod           Where to store the module instance pointer.
+ */
+static int kldrModLXCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
+{
+    PKLDRMODLX pModLX;
+    int rc;
+
+    /*
+     * Create the instance data and do a minimal header validation.
+     */
+    rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX);
+    if (!rc)
+    {
+        pModLX->pMod->pOps = pOps;
+        pModLX->pMod->u32Magic = KLDRMOD_MAGIC;
+        *ppMod = pModLX->pMod;
+        return 0;
+    }
+    kHlpFree(pModLX);
+    return rc;
+}
+
+
+/**
+ * Separate function for reading creating the LX module instance to
+ * simplify cleanup on failure.
+ */
+static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX)
+{
+    struct e32_exe Hdr;
+    PKLDRMODLX pModLX;
+    PKLDRMOD pMod;
+    KSIZE cb;
+    KSIZE cchFilename;
+    KU32 off, offEnd;
+    KU32 i;
+    int rc;
+    int fCanOptimizeMapping;
+    KU32 NextRVA;
+    *ppModLX = NULL;
+
+    /*
+     * Read the signature and file header.
+     */
+    rc = kRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
+    if (rc)
+        return rc;
+    if (    Hdr.e32_magic[0] != E32MAGIC1
+        ||  Hdr.e32_magic[1] != E32MAGIC2)
+        return KLDR_ERR_UNKNOWN_FORMAT;
+
+    /* We're not interested in anything but x86 images. */
+    if (    Hdr.e32_level != E32LEVEL
+        ||  Hdr.e32_border != E32LEBO
+        ||  Hdr.e32_worder != E32LEWO
+        ||  Hdr.e32_cpu < E32CPU286
+        ||  Hdr.e32_cpu > E32CPU486
+        ||  Hdr.e32_pagesize != OBJPAGELEN
+        )
+        return KLDR_ERR_LX_BAD_HEADER;
+
+    /* Some rough sanity checks. */
+    offEnd = kRdrSize(pRdr) >= (KLDRFOFF)~(KU32)16 ? ~(KU32)16 : (KU32)kRdrSize(pRdr);
+    if (    Hdr.e32_itermap > offEnd
+        ||  Hdr.e32_datapage > offEnd
+        ||  Hdr.e32_nrestab > offEnd
+        ||  Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
+        ||  Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
+        ||  Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
+        ||  Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
+        return KLDR_ERR_LX_BAD_HEADER;
+
+    /* Verify the loader section. */
+    offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
+    if (Hdr.e32_objtab < sizeof(Hdr))
+        return KLDR_ERR_LX_BAD_LOADER_SECTION;
+    off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
+    if (off > offEnd)
+        return KLDR_ERR_LX_BAD_LOADER_SECTION;
+    if (    Hdr.e32_objmap
+        &&  (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
+        return KLDR_ERR_LX_BAD_LOADER_SECTION;
+    if (    Hdr.e32_rsrccnt
+        && (   Hdr.e32_rsrctab < off
+            || Hdr.e32_rsrctab > offEnd
+            || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
+        return KLDR_ERR_LX_BAD_LOADER_SECTION;
+    if (    Hdr.e32_restab
+        &&  (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
+        return KLDR_ERR_LX_BAD_LOADER_SECTION;
+    if (    Hdr.e32_enttab
+        &&  (Hdr.e32_enttab < off || Hdr.e32_enttab >= offEnd))
+        return KLDR_ERR_LX_BAD_LOADER_SECTION;
+    if (    Hdr.e32_dircnt
+        && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd - 2))
+        return KLDR_ERR_LX_BAD_LOADER_SECTION;
+
+    /* Verify the fixup section. */
+    off = offEnd;
+    offEnd = off + Hdr.e32_fixupsize;
+    if (    Hdr.e32_fpagetab
+        &&  (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
+    {
+        /*
+         * wlink mixes the fixup section and the loader section.
+         */
+        off = Hdr.e32_fpagetab;
+        offEnd = off + Hdr.e32_fixupsize;
+        Hdr.e32_ldrsize = off - Hdr.e32_objtab;
+    }
+    if (    Hdr.e32_frectab
+        &&  (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
+        return KLDR_ERR_LX_BAD_FIXUP_SECTION;
+    if (    Hdr.e32_impmod
+        &&  (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
+        return KLDR_ERR_LX_BAD_FIXUP_SECTION;
+    if (    Hdr.e32_impproc
+        &&  (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
+        return KLDR_ERR_LX_BAD_FIXUP_SECTION;
+
+    /*
+     * Calc the instance size, allocate and initialize it.
+     */
+    cchFilename = kHlpStrLen(kRdrName(pRdr));
+    cb = K_ALIGN_Z(sizeof(KLDRMODLX), 8)
+       + K_ALIGN_Z(K_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8)
+       + K_ALIGN_Z(cchFilename + 1, 8)
+       + Hdr.e32_ldrsize + 2; /* +2 for two extra zeros. */
+    pModLX = (PKLDRMODLX)kHlpAlloc(cb);
+    if (!pModLX)
+        return KERR_NO_MEMORY;
+    *ppModLX = pModLX;
+
+    /* KLDRMOD */
+    pMod = (PKLDRMOD)((KU8 *)pModLX + K_ALIGN_Z(sizeof(KLDRMODLX), 8));
+    pMod->pvData = pModLX;
+    pMod->pRdr = pRdr;
+    pMod->pOps = NULL;      /* set upon success. */
+    pMod->cSegments = Hdr.e32_objcnt;
+    pMod->cchFilename = cchFilename;
+    pMod->pszFilename = (char *)K_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8);
+    kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1);
+    pMod->pszName = NULL; /* finalized further down */
+    pMod->cchName = 0;
+    switch (Hdr.e32_cpu)
+    {
+        case E32CPU286:
+            pMod->enmCpu = KCPU_I80286;
+            pMod->enmArch = KCPUARCH_X86_16;
+            break;
+        case E32CPU386:
+            pMod->enmCpu = KCPU_I386;
+            pMod->enmArch = KCPUARCH_X86_32;
+            break;
+        case E32CPU486:
+            pMod->enmCpu = KCPU_I486;
+            pMod->enmArch = KCPUARCH_X86_32;
+            break;
+    }
+    pMod->enmEndian = KLDRENDIAN_LITTLE;
+    pMod->enmFmt = KLDRFMT_LX;
+    switch (Hdr.e32_mflags & E32MODMASK)
+    {
+        case E32MODEXE:
+            pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX)
+                ? KLDRTYPE_EXECUTABLE_RELOCATABLE
+                : KLDRTYPE_EXECUTABLE_FIXED;
+            break;
+
+        case E32MODDLL:
+        case E32PROTDLL:
+        case E32MODPROTDLL:
+            pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL)
+                ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
+                : KLDRTYPE_SHARED_LIBRARY_FIXED;
+            break;
+
+        case E32MODPDEV:
+        case E32MODVDEV:
+            pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
+            break;
+    }
+    pMod->u32Magic = 0;     /* set upon success. */
+
+    /* KLDRMODLX */
+    pModLX->pMod = pMod;
+    pModLX->pvMapping = 0;
+    pModLX->cbMapped = 0;
+    pModLX->f32Reserved = 0;
+
+    pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
+    pModLX->Hdr = Hdr;
+
+    pModLX->pbLoaderSection = K_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16);
+    pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize - 1;
+    pModLX->paObjs = NULL;
+    pModLX->paPageMappings = NULL;
+    pModLX->paRsrcs = NULL;
+    pModLX->pbResNameTab = NULL;
+    pModLX->pbEntryTab = NULL;
+
+    pModLX->pbNonResNameTab = NULL;
+    pModLX->pbNonResNameTabLast = NULL;
+
+    pModLX->pbFixupSection = NULL;
+    pModLX->pbFixupSectionLast = NULL;
+    pModLX->paoffPageFixups = NULL;
+    pModLX->pbFixupRecs = NULL;
+    pModLX->pbImportMods = NULL;
+    pModLX->pbImportProcs = NULL;
+
+    /*
+     * Read the loader data.
+     */
+    rc = kRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
+    if (rc)
+        return rc;
+    ((KU8 *)pModLX->pbLoaderSectionLast)[1] = 0;
+    ((KU8 *)pModLX->pbLoaderSectionLast)[2] = 0;
+    if (pModLX->Hdr.e32_objcnt)
+        pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
+    if (pModLX->Hdr.e32_objmap)
+        pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
+    if (pModLX->Hdr.e32_rsrccnt)
+        pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
+    if (pModLX->Hdr.e32_restab)
+        pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
+    if (pModLX->Hdr.e32_enttab)
+        pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
+
+    /*
+     * Get the soname from the resident name table.
+     * Very convenient that it's the 0 ordinal, because then we get a
+     * free string terminator.
+     * (The table entry consists of a pascal string followed by a 16-bit ordinal.)
+     */
+    if (pModLX->pbResNameTab)
+        pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab,
+                                                                          pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
+                                                                          0);
+    if (!pMod->pszName)
+        return KLDR_ERR_LX_NO_SONAME;
+    pMod->cchName = *(const KU8 *)pMod->pszName++;
+    if (pMod->cchName != kHlpStrLen(pMod->pszName))
+        return KLDR_ERR_LX_BAD_SONAME;
+
+    /*
+     * Quick validation of the object table.
+     */
+    cb = 0;
+    for (i = 0; i < pMod->cSegments; i++)
+    {
+        if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
+            return KLDR_ERR_LX_BAD_OBJECT_TABLE;
+        if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
+            return KLDR_ERR_LX_BAD_OBJECT_TABLE;
+        if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1)))
+            return KLDR_ERR_LX_BAD_OBJECT_TABLE;
+        if (    pModLX->paObjs[i].o32_mapsize
+            &&  (   (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
+                 || (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
+                     > pModLX->pbLoaderSectionLast))
+            return KLDR_ERR_LX_BAD_OBJECT_TABLE;
+        if (i > 0 && !(pModLX->paObjs[i].o32_flags & OBJRSRC))
+        {
+            if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
+                return KLDR_ERR_LX_BAD_OBJECT_TABLE;
+            if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
+                return KLDR_ERR_LX_BAD_OBJECT_TABLE;
+        }
+    }
+
+    /*
+     * Check if we can optimize the mapping by using a different
+     * object alignment. The linker typically uses 64KB alignment,
+     * we can easily get away with page alignment in most cases.
+     */
+    fCanOptimizeMapping = !(Hdr.e32_mflags & (E32NOINTFIX | E32SYSDLL));
+    NextRVA = 0;
+
+    /*
+     * Setup the KLDRMOD segment array.
+     */
+    for (i = 0; i < pMod->cSegments; i++)
+    {
+        /* unused */
+        pMod->aSegments[i].pvUser = NULL;
+        pMod->aSegments[i].MapAddress = 0;
+        pMod->aSegments[i].pchName = NULL;
+        pMod->aSegments[i].cchName = 0;
+        pMod->aSegments[i].offFile = -1;
+        pMod->aSegments[i].cbFile = -1;
+        pMod->aSegments[i].SelFlat = 0;
+        pMod->aSegments[i].Sel16bit = 0;
+
+        /* flags */
+        pMod->aSegments[i].fFlags = 0;
+        if (pModLX->paObjs[i].o32_flags & OBJBIGDEF)
+            pMod->aSegments[i].fFlags = KLDRSEG_FLAG_16BIT;
+        if (pModLX->paObjs[i].o32_flags & OBJALIAS16)
+            pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_ALIAS16;
+        if (pModLX->paObjs[i].o32_flags & OBJCONFORM)
+            pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_CONFORM;
+        if (pModLX->paObjs[i].o32_flags & OBJIOPL)
+            pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_IOPL;
+
+        /* size and addresses */
+        pMod->aSegments[i].Alignment   = OBJPAGELEN;
+        pMod->aSegments[i].cb          = pModLX->paObjs[i].o32_size;
+        pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
+        pMod->aSegments[i].RVA         = NextRVA;
+        if (    fCanOptimizeMapping
+            ||  i + 1 >= pMod->cSegments
+            ||  (pModLX->paObjs[i].o32_flags & OBJRSRC)
+            ||  (pModLX->paObjs[i + 1].o32_flags & OBJRSRC))
+            pMod->aSegments[i].cbMapped = K_ALIGN_Z(pModLX->paObjs[i].o32_size, OBJPAGELEN);
+        else
+            pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
+        NextRVA += pMod->aSegments[i].cbMapped;
+
+        /* protection */
+        switch (  pModLX->paObjs[i].o32_flags
+                & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
+        {
+            case 0:
+            case OBJSHARED:
+                pMod->aSegments[i].enmProt = KPROT_NOACCESS;
+                break;
+            case OBJREAD:
+            case OBJREAD | OBJSHARED:
+                pMod->aSegments[i].enmProt = KPROT_READONLY;
+                break;
+            case OBJWRITE:
+            case OBJWRITE | OBJREAD:
+                pMod->aSegments[i].enmProt = KPROT_WRITECOPY;
+                break;
+            case OBJWRITE | OBJSHARED:
+            case OBJWRITE | OBJSHARED | OBJREAD:
+                pMod->aSegments[i].enmProt = KPROT_READWRITE;
+                break;
+            case OBJEXEC:
+            case OBJEXEC | OBJSHARED:
+                pMod->aSegments[i].enmProt = KPROT_EXECUTE;
+                break;
+            case OBJEXEC | OBJREAD:
+            case OBJEXEC | OBJREAD | OBJSHARED:
+                pMod->aSegments[i].enmProt = KPROT_EXECUTE_READ;
+                break;
+            case OBJEXEC | OBJWRITE:
+            case OBJEXEC | OBJWRITE | OBJREAD:
+                pMod->aSegments[i].enmProt = KPROT_EXECUTE_WRITECOPY;
+                break;
+            case OBJEXEC | OBJWRITE | OBJSHARED:
+            case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
+                pMod->aSegments[i].enmProt = KPROT_EXECUTE_READWRITE;
+                break;
+        }
+        if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
+            pMod->aSegments[i].enmProt = KPROT_READONLY;
+        /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
+        pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
+        pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */
+    }
+
+    /* set the mapping size */
+    pModLX->cbMapped = NextRVA;
+
+    /*
+     * We're done.
+     */
+    *ppModLX = pModLX;
+    return 0;
+}
+
+
+/** @copydoc KLDRMODOPS::pfnDestroy */
+static int kldrModLXDestroy(PKLDRMOD pMod)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    int rc = 0;
+    KLDRMODLX_ASSERT(!pModLX->pvMapping);
+
+    if (pMod->pRdr)
+    {
+        rc = kRdrClose(pMod->pRdr);
+        pMod->pRdr = NULL;
+    }
+    if (pModLX->pbNonResNameTab)
+    {
+        kHlpFree(pModLX->pbNonResNameTab);
+        pModLX->pbNonResNameTab = NULL;
+    }
+    if (pModLX->pbFixupSection)
+    {
+        kHlpFree(pModLX->pbFixupSection);
+        pModLX->pbFixupSection = NULL;
+    }
+    pMod->u32Magic = 0;
+    pMod->pOps = NULL;
+    kHlpFree(pModLX);
+    return rc;
+}
+
+
+/**
+ * Resolved base address aliases.
+ *
+ * @param   pModLX          The interpreter module instance
+ * @param   pBaseAddress    The base address, IN & OUT.
+ */
+static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress)
+{
+    if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
+        *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress;
+    else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
+        *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress;
+}
+
+
+/** @copydoc kLdrModQuerySymbol */
+static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
+                                const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                                PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
+{
+    PKLDRMODLX                  pModLX = (PKLDRMODLX)pMod->pvData;
+    KU32                        iOrdinal;
+    int                         rc;
+    const struct b32_bundle     *pBundle;
+
+
+    /*
+     * Give up at once if there is no entry table.
+     */
+    if (!pModLX->Hdr.e32_enttab)
+        return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+    /*
+     * Translate the symbol name into an ordinal.
+     */
+    if (pchSymbol)
+    {
+        rc = kldrModLXDoNameLookup(pModLX, pchSymbol, cchSymbol, &iSymbol);
+        if (rc)
+            return rc;
+    }
+
+    /*
+     * Iterate the entry table.
+     * (The entry table is made up of bundles of similar exports.)
+     */
+    iOrdinal = 1;
+    pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
+    while (pBundle->b32_cnt && iOrdinal <= iSymbol)
+    {
+        static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 };
+
+        /*
+         * Check for a hit first.
+         */
+        iOrdinal += pBundle->b32_cnt;
+        if (iSymbol < iOrdinal)
+        {
+            KU32 offObject;
+            const struct e32_entry *pEntry = (const struct e32_entry *)((KUPTR)(pBundle + 1)
+                                                                        +   (iSymbol - (iOrdinal - pBundle->b32_cnt))
+                                                                          * s_cbEntry[pBundle->b32_type]);
+
+            /*
+             * Calculate the return address.
+             */
+            kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
+            switch (pBundle->b32_type)
+            {
+                /* empty bundles are place holders unused ordinal ranges. */
+                case EMPTY:
+                    return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+                /* e32_flags + a 16-bit offset. */
+                case ENTRY16:
+                    offObject = pEntry->e32_variant.e32_offset.offset16;
+                    if (pfKind)
+                        *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE;
+                    break;
+
+                /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
+                case GATE16:
+                    offObject = pEntry->e32_variant.e32_callgate.offset;
+                    if (pfKind)
+                        *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE;
+                    break;
+
+                /* e32_flags + a 32-bit offset. */
+                case ENTRY32:
+                    offObject = pEntry->e32_variant.e32_offset.offset32;
+                    if (pfKind)
+                        *pfKind = KLDRSYMKIND_32BIT;
+                    break;
+
+                /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
+                case ENTRYFWD:
+                    return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind);
+
+                default:
+                    /* anyone actually using TYPEINFO will end up here. */
+                    KLDRMODLX_ASSERT(!"Bad bundle type");
+                    return KLDR_ERR_LX_BAD_BUNDLE;
+            }
+
+            /*
+             * Validate the object number and calc the return address.
+             */
+            if (    pBundle->b32_obj <= 0
+                ||  pBundle->b32_obj > pMod->cSegments)
+                return KLDR_ERR_LX_BAD_BUNDLE;
+            if (puValue)
+                *puValue = BaseAddress
+                         + offObject
+                         + pMod->aSegments[pBundle->b32_obj - 1].RVA;
+            return 0;
+        }
+
+        /*
+         * Skip the bundle.
+         */
+        if (pBundle->b32_type > ENTRYFWD)
+        {
+            KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
+            return KLDR_ERR_LX_BAD_BUNDLE;
+        }
+        if (pBundle->b32_type == 0)
+            pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2);
+        else
+            pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
+    }
+
+    return KLDR_ERR_SYMBOL_NOT_FOUND;
+}
+
+
+/**
+ * Do name lookup.
+ *
+ * @returns See kLdrModQuerySymbol.
+ * @param   pModLX      The module to lookup the symbol in.
+ * @param   pchSymbol   The symbol to lookup.
+ * @param   cchSymbol   The symbol name length.
+ * @param   piSymbol    Where to store the symbol ordinal.
+ */
+static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KU32 cchSymbol, KU32 *piSymbol)
+{
+
+    /*
+     * First do a hash table lookup.
+     */
+    /** @todo hash name table for speed. */
+
+    /*
+     * Search the name tables.
+     */
+    const KU8 *pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab,
+                                                         pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
+                                                         pchSymbol, cchSymbol);
+    if (!pbName)
+    {
+        if (!pModLX->pbNonResNameTab)
+        {
+            /* lazy load it */
+            /** @todo non-resident name table. */
+        }
+        if (pModLX->pbNonResNameTab)
+            pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab,
+                                                      pModLX->pbNonResNameTabLast - pModLX->pbResNameTab + 1,
+                                                      pchSymbol, cchSymbol);
+    }
+    if (!pbName)
+        return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+    *piSymbol = *(const KU16 *)(pbName + 1 + *pbName);
+    return 0;
+}
+
+
+#if 0
+/**
+ * Hash a symbol using the algorithm from sdbm.
+ *
+ * The following was is the documenation of the orignal sdbm functions:
+ *
+ * This algorithm was created for sdbm (a public-domain reimplementation of
+ * ndbm) database library. it was found to do well in scrambling bits,
+ * causing better distribution of the keys and fewer splits. it also happens
+ * to be a good general hashing function with good distribution. the actual
+ * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
+ * is the faster version used in gawk. [there is even a faster, duff-device
+ * version] the magic constant 65599 was picked out of thin air while
+ * experimenting with different constants, and turns out to be a prime.
+ * this is one of the algorithms used in berkeley db (see sleepycat) and
+ * elsewhere.
+ */
+static KU32 kldrModLXDoHash(const char *pchSymbol, KU8 cchSymbol)
+{
+    KU32 hash = 0;
+    int ch;
+
+    while (     cchSymbol-- > 0
+           &&   (ch = *(unsigned const char *)pchSymbol++))
+        hash = ch + (hash << 6) + (hash << 16) - hash;
+
+    return hash;
+}
+#endif
+
+
+/**
+ * Lookup a name table entry by name.
+ *
+ * @returns Pointer to the name table entry if found.
+ * @returns NULL if not found.
+ * @param   pbNameTable     Pointer to the name table that should be searched.
+ * @param   cbNameTable     The size of the name table.
+ * @param   pchSymbol       The name of the symbol we're looking for.
+ * @param   cchSymbol       The length of the symbol name.
+ */
+static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KI32 cbNameTable,
+                                                   const char *pchSymbol, KSIZE cchSymbol)
+{
+    /*
+     * Determin the namelength up front so we can skip anything which doesn't matches the length.
+     */
+    KU8 cbSymbol8Bit = (KU8)cchSymbol;
+    if (cbSymbol8Bit != cchSymbol)
+        return NULL; /* too long. */
+
+    /*
+     * Walk the name table.
+     */
+    while (*pbNameTable != 0 && cbNameTable > 0)
+    {
+        const KU8 cbName = *pbNameTable;
+
+        cbNameTable -= cbName + 1 + 2;
+        if (cbNameTable < 0)
+            break;
+
+        if (    cbName == cbSymbol8Bit
+            &&  !kHlpMemComp(pbNameTable + 1, pchSymbol, cbName))
+            return pbNameTable;
+
+        /* next entry */
+        pbNameTable += cbName + 1 + 2;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Deal with a forwarder entry.
+ *
+ * @returns See kLdrModQuerySymbol.
+ * @param   pModLX          The PE module interpreter instance.
+ * @param   pEntry          The forwarder entry.
+ * @param   pfnGetForwarder The callback for resolving forwarder symbols. (optional)
+ * @param   pvUser          The user argument for the callback.
+ * @param   puValue         Where to put the value. (optional)
+ * @param   pfKind          Where to put the symbol kind. (optional)
+ */
+static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
+                                     PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
+{
+    int rc;
+    KU32 iSymbol;
+    const char *pchSymbol;
+    KU8 cchSymbol;
+
+    if (!pfnGetForwarder)
+        return KLDR_ERR_FORWARDER_SYMBOL;
+
+    /*
+     * Validate the entry import module ordinal.
+     */
+    if (    !pEntry->e32_variant.e32_fwd.modord
+        ||  pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt)
+        return KLDR_ERR_LX_BAD_FORWARDER;
+
+    /*
+     * Figure out the parameters.
+     */
+    if (pEntry->e32_flags & FWD_ORDINAL)
+    {
+        iSymbol = pEntry->e32_variant.e32_fwd.value;
+        pchSymbol = NULL;                   /* no symbol name. */
+        cchSymbol = 0;
+    }
+    else
+    {
+        const KU8 *pbName;
+
+        /* load the fixup section if necessary. */
+        if (!pModLX->pbImportProcs)
+        {
+            rc = kldrModLXDoLoadFixupSection(pModLX);
+            if (rc)
+                return rc;
+        }
+
+        /* Make name pointer. */
+        pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value;
+        if (    pbName >= pModLX->pbFixupSectionLast
+            ||  pbName < pModLX->pbFixupSection
+            || !*pbName)
+            return KLDR_ERR_LX_BAD_FORWARDER;
+
+
+        /* check for '#' name. */
+        if (pbName[1] == '#')
+        {
+            KU8         cbLeft = *pbName;
+            const KU8  *pb = pbName + 1;
+            unsigned    uBase;
+
+            /* base detection */
+            uBase = 10;
+            if (    cbLeft > 1
+                &&  pb[1] == '0'
+                &&  (pb[2] == 'x' || pb[2] == 'X'))
+            {
+                uBase = 16;
+                pb += 2;
+                cbLeft -= 2;
+            }
+
+            /* ascii to integer */
+            iSymbol = 0;
+            while (cbLeft-- > 0)
+            {
+                /* convert char to digit. */
+                unsigned uDigit = *pb++;
+                if (uDigit >= '0' && uDigit <= '9')
+                    uDigit -= '0';
+                else if (uDigit >= 'a' && uDigit <= 'z')
+                    uDigit -= 'a' + 10;
+                else if (uDigit >= 'A' && uDigit <= 'Z')
+                    uDigit -= 'A' + 10;
+                else if (!uDigit)
+                    break;
+                else
+                    return KLDR_ERR_LX_BAD_FORWARDER;
+                if (uDigit >= uBase)
+                    return KLDR_ERR_LX_BAD_FORWARDER;
+
+                /* insert the digit */
+                iSymbol *= uBase;
+                iSymbol += uDigit;
+            }
+            if (!iSymbol)
+                return KLDR_ERR_LX_BAD_FORWARDER;
+
+            pchSymbol = NULL;               /* no symbol name. */
+            cchSymbol = 0;
+        }
+        else
+        {
+            pchSymbol = (char *)pbName + 1;
+            cchSymbol = *pbName;
+            iSymbol = NIL_KLDRMOD_SYM_ORDINAL;
+        }
+    }
+
+    /*
+     * Resolve the forwarder.
+     */
+    rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pchSymbol, cchSymbol, NULL, puValue, pfKind, pvUser);
+    if (!rc && pfKind)
+        *pfKind |= KLDRSYMKIND_FORWARDER;
+    return rc;
+}
+
+
+/**
+ * Loads the fixup section from the executable image.
+ *
+ * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone().
+ *
+ * @returns 0 on success, non-zero kLdr or native status code on failure.
+ * @param   pModLX          The PE module interpreter instance.
+ */
+static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX)
+{
+    int rc;
+    KU32 off;
+    void *pv;
+
+    pv = kHlpAlloc(pModLX->Hdr.e32_fixupsize);
+    if (!pv)
+        return KERR_NO_MEMORY;
+
+    off = pModLX->Hdr.e32_objtab + pModLX->Hdr.e32_ldrsize;
+    rc = kRdrRead(pModLX->pMod->pRdr, pv, pModLX->Hdr.e32_fixupsize,
+                     off + pModLX->offHdr);
+    if (!rc)
+    {
+        pModLX->pbFixupSection = pv;
+        pModLX->pbFixupSectionLast = pModLX->pbFixupSection + pModLX->Hdr.e32_fixupsize;
+        KLDRMODLX_ASSERT(!pModLX->paoffPageFixups);
+        if (pModLX->Hdr.e32_fpagetab)
+            pModLX->paoffPageFixups = (const KU32 *)(pModLX->pbFixupSection + pModLX->Hdr.e32_fpagetab - off);
+        KLDRMODLX_ASSERT(!pModLX->pbFixupRecs);
+        if (pModLX->Hdr.e32_frectab)
+            pModLX->pbFixupRecs = pModLX->pbFixupSection + pModLX->Hdr.e32_frectab - off;
+        KLDRMODLX_ASSERT(!pModLX->pbImportMods);
+        if (pModLX->Hdr.e32_impmod)
+            pModLX->pbImportMods = pModLX->pbFixupSection + pModLX->Hdr.e32_impmod - off;
+        KLDRMODLX_ASSERT(!pModLX->pbImportProcs);
+        if (pModLX->Hdr.e32_impproc)
+            pModLX->pbImportProcs = pModLX->pbFixupSection + pModLX->Hdr.e32_impproc - off;
+    }
+    else
+        kHlpFree(pv);
+    return rc;
+}
+
+
+/** @copydoc kLdrModEnumSymbols */
+static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
+                                KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    const struct b32_bundle *pBundle;
+    KU32 iOrdinal;
+    int rc = 0;
+
+    kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
+
+    /*
+     * Enumerate the entry table.
+     * (The entry table is made up of bundles of similar exports.)
+     */
+    iOrdinal = 1;
+    pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
+    while (pBundle->b32_cnt && iOrdinal)
+    {
+        static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 };
+
+        /*
+         * Enum the entries in the bundle.
+         */
+        if (pBundle->b32_type != EMPTY)
+        {
+            const struct e32_entry *pEntry;
+            KSIZE cbEntry;
+            KLDRADDR BundleRVA;
+            unsigned cLeft;
+
+
+            /* Validate the bundle. */
+            switch (pBundle->b32_type)
+            {
+                case ENTRY16:
+                case GATE16:
+                case ENTRY32:
+                    if (    pBundle->b32_obj <= 0
+                        ||  pBundle->b32_obj > pMod->cSegments)
+                        return KLDR_ERR_LX_BAD_BUNDLE;
+                    BundleRVA = pMod->aSegments[pBundle->b32_obj - 1].RVA;
+                    break;
+
+                case ENTRYFWD:
+                    BundleRVA = 0;
+                    break;
+
+                default:
+                    /* anyone actually using TYPEINFO will end up here. */
+                    KLDRMODLX_ASSERT(!"Bad bundle type");
+                    return KLDR_ERR_LX_BAD_BUNDLE;
+            }
+
+            /* iterate the bundle entries. */
+            cbEntry = s_cbEntry[pBundle->b32_type];
+            pEntry = (const struct e32_entry *)(pBundle + 1);
+            cLeft = pBundle->b32_cnt;
+            while (cLeft-- > 0)
+            {
+                KLDRADDR uValue;
+                KU32 fKind;
+                int fFoundName;
+                const KU8 *pbName;
+
+                /*
+                 * Calc the symbol value and kind.
+                 */
+                switch (pBundle->b32_type)
+                {
+                    /* e32_flags + a 16-bit offset. */
+                    case ENTRY16:
+                        uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset16;
+                        fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE;
+                        break;
+
+                    /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
+                    case GATE16:
+                        uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_callgate.offset;
+                        fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE;
+                        break;
+
+                    /* e32_flags + a 32-bit offset. */
+                    case ENTRY32:
+                        uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset32;
+                        fKind = KLDRSYMKIND_32BIT;
+                        break;
+
+                    /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
+                    case ENTRYFWD:
+                        uValue = 0; /** @todo implement enumeration of forwarders properly. */
+                        fKind = KLDRSYMKIND_FORWARDER;
+                        break;
+                }
+
+                /*
+                 * Any symbol names?
+                 */
+                fFoundName = 0;
+
+                /* resident name table. */
+                pbName = pModLX->pbResNameTab;
+                if (pbName)
+                {
+                    do
+                    {
+                        pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbLoaderSectionLast - pbName + 1, iOrdinal);
+                        if (!pbName)
+                            break;
+                        fFoundName = 1;
+                        rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser);
+                        if (rc)
+                            return rc;
+
+                        /* skip to the next entry */
+                        pbName += 1 + *pbName + 2;
+                    } while (pbName < pModLX->pbLoaderSectionLast);
+                }
+
+                /* resident name table. */
+                pbName = pModLX->pbNonResNameTab;
+                /** @todo lazy load the non-resident name table. */
+                if (pbName)
+                {
+                    do
+                    {
+                        pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbNonResNameTabLast - pbName + 1, iOrdinal);
+                        if (!pbName)
+                            break;
+                        fFoundName = 1;
+                        rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser);
+                        if (rc)
+                            return rc;
+
+                        /* skip to the next entry */
+                        pbName += 1 + *pbName + 2;
+                    } while (pbName < pModLX->pbLoaderSectionLast);
+                }
+
+                /*
+                 * If no names, call once with the ordinal only.
+                 */
+                if (!fFoundName)
+                {
+                    rc = pfnCallback(pMod, iOrdinal, NULL, 0, NULL, uValue, fKind, pvUser);
+                    if (rc)
+                        return rc;
+                }
+
+                /* next */
+                iOrdinal++;
+                pEntry = (const struct e32_entry *)((KUPTR)pEntry + cbEntry);
+            }
+        }
+
+        /*
+         * The next bundle.
+         */
+        if (pBundle->b32_type > ENTRYFWD)
+        {
+            KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
+            return KLDR_ERR_LX_BAD_BUNDLE;
+        }
+        if (pBundle->b32_type == 0)
+            pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2);
+        else
+            pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
+    }
+
+    return 0;
+}
+
+
+/**
+ * Lookup a name table entry by ordinal.
+ *
+ * @returns Pointer to the name table entry if found.
+ * @returns NULL if not found.
+ * @param   pbNameTable Pointer to the name table that should be searched.
+ * @param   cbNameTable The size of the name table.
+ * @param   iOrdinal    The ordinal to search for.
+ */
+static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KI32 cbNameTable, KU32 iOrdinal)
+{
+    while (*pbNameTable != 0 && cbNameTable > 0)
+    {
+        const KU8   cbName = *pbNameTable;
+        KU32        iName;
+
+        cbNameTable -= cbName + 1 + 2;
+        if (cbNameTable < 0)
+            break;
+
+        iName = *(pbNameTable + cbName + 1)
+              | ((unsigned)*(pbNameTable + cbName + 2) << 8);
+        if (iName == iOrdinal)
+            return pbNameTable;
+
+        /* next entry */
+        pbNameTable += cbName + 1 + 2;
+    }
+
+    return NULL;
+}
+
+
+/** @copydoc kLdrModGetImport */
+static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
+{
+    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
+    const KU8  *pb;
+    int         rc;
+
+    /*
+     * Validate
+     */
+    if (iImport >= pModLX->Hdr.e32_impmodcnt)
+        return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
+
+    /*
+     * Lazy loading the fixup section.
+     */
+    if (!pModLX->pbImportMods)
+    {
+        rc = kldrModLXDoLoadFixupSection(pModLX);
+        if (rc)
+            return rc;
+    }
+
+    /*
+     * Iterate the module import table until we reach the requested import ordinal.
+     */
+    pb = pModLX->pbImportMods;
+    while (iImport-- > 0)
+        pb += *pb + 1;
+
+    /*
+     * Copy out the result.
+     */
+    if (*pb < cchName)
+    {
+        kHlpMemCopy(pszName, pb + 1, *pb);
+        pszName[*pb] = '\0';
+        rc = 0;
+    }
+    else
+    {
+        kHlpMemCopy(pszName, pb + 1, cchName);
+        if (cchName)
+            pszName[cchName - 1] = '\0';
+        rc = KERR_BUFFER_OVERFLOW;
+    }
+
+    return rc;
+}
+
+
+/** @copydoc kLdrModNumberOfImports */
+static KI32 kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    return pModLX->Hdr.e32_impmodcnt;
+}
+
+
+/** @copydoc kLdrModGetStackInfo */
+static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    const KU32 i = pModLX->Hdr.e32_stackobj;
+
+    if (    i
+        &&  i <= pMod->cSegments
+        &&  pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb
+        &&  pModLX->Hdr.e32_stacksize
+        &&  pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress)
+    {
+
+        kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
+        pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
+        pStackInfo->Address = BaseAddress
+                            + pMod->aSegments[i - 1].RVA
+                            + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress;
+    }
+    else
+    {
+        pStackInfo->Address = NIL_KLDRADDR;
+        pStackInfo->LinkAddress = NIL_KLDRADDR;
+    }
+    pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
+    pStackInfo->cbStackThread = 0;
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModQueryMainEntrypoint */
+static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+
+    /*
+     * Convert the address from the header.
+     */
+    kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
+    *pMainEPAddress = pModLX->Hdr.e32_startobj
+                   && pModLX->Hdr.e32_startobj <= pMod->cSegments
+                   && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb
+        ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
+        : NIL_KLDRADDR;
+    return 0;
+}
+
+
+/** @copydoc kLdrModEnumDbgInfo */
+static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
+{
+    /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/
+
+    /*
+     * Quit immediately if no debug info.
+     */
+    if (kldrModLXHasDbgInfo(pMod, pvBits))
+        return 0;
+#if 0
+    /*
+     * Read the debug info and look for familiar magics and structures.
+     */
+    /** @todo */
+#endif
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModHasDbgInfo */
+static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+
+    /*
+     * Don't curretnly bother with linkers which doesn't advertise it in the header.
+     */
+    if (    !pModLX->Hdr.e32_debuginfo
+        ||  !pModLX->Hdr.e32_debuglen)
+        return KLDR_ERR_NO_DEBUG_INFO;
+    return 0;
+}
+
+
+/** @copydoc kLdrModMap */
+static int kldrModLXMap(PKLDRMOD pMod)
+{
+    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
+    unsigned    fFixed;
+    void       *pvBase;
+    int         rc;
+
+    /*
+     * Already mapped?
+     */
+    if (pModLX->pvMapping)
+        return KLDR_ERR_ALREADY_MAPPED;
+
+    /*
+     * Allocate memory for it.
+     */
+    /* fixed image? */
+    fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
+          || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
+    if (!fFixed)
+        pvBase = NULL;
+    else
+    {
+        pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
+        if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
+            return KLDR_ERR_ADDRESS_OVERFLOW;
+    }
+    rc = kHlpPageAlloc(&pvBase, pModLX->cbMapped, KPROT_EXECUTE_READWRITE, fFixed);
+    if (rc)
+        return rc;
+
+    /*
+     * Load the bits, apply page protection, and update the segment table.
+     */
+    rc = kldrModLXDoLoadBits(pModLX, pvBase);
+    if (!rc)
+        rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
+    if (!rc)
+    {
+        KU32 i;
+        for (i = 0; i < pMod->cSegments; i++)
+        {
+            if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
+                pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
+        }
+        pModLX->pvMapping = pvBase;
+    }
+    else
+        kHlpPageFree(pvBase, pModLX->cbMapped);
+    return rc;
+}
+
+
+/**
+ * Loads the LX pages into the specified memory mapping.
+ *
+ * @returns 0 on success.
+ * @returns non-zero kLdr or OS status code on failure.
+ *
+ * @param   pModLX  The LX module interpreter instance.
+ * @param   pvBits  Where to load the bits.
+ */
+static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
+{
+    const PKRDR pRdr = pModLX->pMod->pRdr;
+    KU8 *pbTmpPage = NULL;
+    int rc = 0;
+    KU32 i;
+
+    /*
+     * Iterate the segments.
+     */
+    for (i = 0; i < pModLX->Hdr.e32_objcnt; i++)
+    {
+        const struct o32_obj * const pObj = &pModLX->paObjs[i];
+        const KU32      cPages = pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN;
+        KU32            iPage;
+        KU8            *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[i].RVA;
+
+        /*
+         * Iterate the page map pages.
+         */
+        for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN)
+        {
+            const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1];
+            switch (pMap->o32_pageflags)
+            {
+                case VALID:
+                    if (pMap->o32_pagesize == OBJPAGELEN)
+                        rc = kRdrRead(pRdr, pbPage, OBJPAGELEN,
+                                         pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
+                    else if (pMap->o32_pagesize < OBJPAGELEN)
+                    {
+                        rc = kRdrRead(pRdr, pbPage, pMap->o32_pagesize,
+                                         pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
+                        kHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize);
+                    }
+                    else
+                        rc = KLDR_ERR_LX_BAD_PAGE_MAP;
+                    break;
+
+                case ITERDATA:
+                case ITERDATA2:
+                    /* make sure we've got a temp page .*/
+                    if (!pbTmpPage)
+                    {
+                        pbTmpPage = kHlpAlloc(OBJPAGELEN + 256);
+                        if (!pbTmpPage)
+                            break;
+                    }
+                    /* validate the size. */
+                    if (pMap->o32_pagesize > OBJPAGELEN + 252)
+                    {
+                        rc = KLDR_ERR_LX_BAD_PAGE_MAP;
+                        break;
+                    }
+
+                    /* read it and ensure 4 extra zero bytes. */
+                    rc = kRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize,
+                                     pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift));
+                    if (rc)
+                        break;
+                    kHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4);
+
+                    /* unpack it into the image page. */
+                    if (pMap->o32_pageflags == ITERDATA2)
+                        rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
+                    else
+                        rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
+                    break;
+
+                case INVALID: /* we're probably not dealing correctly with INVALID pages... */
+                case ZEROED:
+                    kHlpMemSet(pbPage, 0, OBJPAGELEN);
+                    break;
+
+                case RANGE:
+                    KLDRMODLX_ASSERT(!"RANGE");
+                default:
+                    rc = KLDR_ERR_LX_BAD_PAGE_MAP;
+                    break;
+            }
+        }
+        if (rc)
+            break;
+
+        /*
+         * Zero the remaining pages.
+         */
+        if (iPage < cPages)
+            kHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN);
+    }
+
+    if (pbTmpPage)
+        kHlpFree(pbTmpPage);
+    return rc;
+}
+
+
+/**
+ * Unpacks iterdata (aka EXEPACK).
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pbDst       Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
+ * @param   pbSrc       The compressed source data.
+ * @param   cbSrc       The file size of the compressed data. The source buffer
+ *                      contains 4 additional zero bytes.
+ */
+static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc)
+{
+    const struct LX_Iter   *pIter = (const struct LX_Iter *)pbSrc;
+    int                     cbDst = OBJPAGELEN;
+
+    /* Validate size of data. */
+    if (cbSrc >= OBJPAGELEN - 2)
+        return KLDR_ERR_LX_BAD_ITERDATA;
+
+    /*
+     * Expand the page.
+     */
+    while (cbSrc > 0 && pIter->LX_nIter)
+    {
+        if (pIter->LX_nBytes == 1)
+        {
+            /*
+             * Special case - one databyte.
+             */
+            cbDst -= pIter->LX_nIter;
+            if (cbDst < 0)
+                return KLDR_ERR_LX_BAD_ITERDATA;
+
+            cbSrc -= 4 + 1;
+            if (cbSrc < -4)
+                return KLDR_ERR_LX_BAD_ITERDATA;
+
+            kHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter);
+            pbDst += pIter->LX_nIter;
+            pIter++;
+        }
+        else
+        {
+            /*
+             * General.
+             */
+            int i;
+
+            cbDst -= pIter->LX_nIter * pIter->LX_nBytes;
+            if (cbDst < 0)
+                return KLDR_ERR_LX_BAD_ITERDATA;
+
+            cbSrc -= 4 + pIter->LX_nBytes;
+            if (cbSrc < -4)
+                return KLDR_ERR_LX_BAD_ITERDATA;
+
+            for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes)
+                kHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes);
+            pIter   = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
+        }
+    }
+
+    /*
+     * Zero remainder of the page.
+     */
+    if (cbDst > 0)
+        kHlpMemSet(pbDst, 0, cbDst);
+
+    return 0;
+}
+
+
+/**
+ * Unpacks iterdata (aka EXEPACK).
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pbDst       Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
+ * @param   pbSrc       The compressed source data.
+ * @param   cbSrc       The file size of the compressed data. The source buffer
+ *                      contains 4 additional zero bytes.
+ */
+static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc)
+{
+    int cbDst = OBJPAGELEN;
+
+    while (cbSrc > 0)
+    {
+        /*
+         * Bit 0 and 1 is the encoding type.
+         */
+        switch (*pbSrc & 0x03)
+        {
+            /*
+             *
+             *  0  1  2  3  4  5  6  7
+             *  type  |              |
+             *        ----------------
+             *             cb         <cb bytes of data>
+             *
+             * Bits 2-7 is, if not zero, the length of an uncompressed run
+             * starting at the following byte.
+             *
+             *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+             *  type  |              |  |                    | |                     |
+             *        ----------------  ---------------------- -----------------------
+             *             zero                 cb                 char to multiply
+             *
+             * If the bits are zero, the following two bytes describes a 1 byte interation
+             * run. First byte is count, second is the byte to copy. A count of zero is
+             * means end of data, and we simply stops. In that case the rest of the data
+             * should be zero.
+             */
+            case 0:
+            {
+                if (*pbSrc)
+                {
+                    const int cb = *pbSrc >> 2;
+                    cbDst -= cb;
+                    if (cbDst < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    cbSrc -= cb + 1;
+                    if (cbSrc < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    kHlpMemCopy(pbDst, ++pbSrc, cb);
+                    pbDst += cb;
+                    pbSrc += cb;
+                }
+                else if (cbSrc < 2)
+                    return KLDR_ERR_LX_BAD_ITERDATA2;
+                else
+                {
+                    const int cb = pbSrc[1];
+                    if (!cb)
+                        goto l_endloop;
+                    cbDst -= cb;
+                    if (cbDst < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    cbSrc -= 3;
+                    if (cbSrc < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    kHlpMemSet(pbDst, pbSrc[2], cb);
+                    pbDst += cb;
+                    pbSrc += 3;
+                }
+                break;
+            }
+
+
+            /*
+             *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+             *  type  |  |  |     |  |                       |
+             *        ----  -------  -------------------------
+             *        cb1   cb2 - 3          offset            <cb1 bytes of data>
+             *
+             * Two bytes layed out as described above, followed by cb1 bytes of data to be copied.
+             * The cb2(+3) and offset describes an amount of data to be copied from the expanded
+             * data relative to the current position. The data copied as you would expect it to be.
+             */
+            case 1:
+            {
+                cbSrc -= 2;
+                if (cbSrc < 0)
+                    return KLDR_ERR_LX_BAD_ITERDATA2;
+                else
+                {
+                    const unsigned  off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7);
+                    const int       cb1 = (*pbSrc >> 2) & 3;
+                    const int       cb2 = ((*pbSrc >> 4) & 7) + 3;
+
+                    pbSrc += 2;
+                    cbSrc -= cb1;
+                    if (cbSrc < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    cbDst -= cb1;
+                    if (cbDst < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    kHlpMemCopy(pbDst, pbSrc, cb1);
+                    pbDst += cb1;
+                    pbSrc += cb1;
+
+                    if (off > OBJPAGELEN - cbDst)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    cbDst -= cb2;
+                    if (cbDst < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    kHlpMemMove(pbDst, pbDst - off, cb2);
+                    pbDst += cb2;
+                }
+                break;
+            }
+
+
+            /*
+             *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+             *  type  |  |  |                                |
+             *        ----  ----------------------------------
+             *       cb-3               offset
+             *
+             * Two bytes layed out as described above.
+             * The cb(+3) and offset describes an amount of data to be copied from the expanded
+             * data relative to the current position.
+             *
+             * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
+             */
+            case 2:
+            {
+                cbSrc -= 2;
+                if (cbSrc < 0)
+                    return KLDR_ERR_LX_BAD_ITERDATA2;
+                else
+                {
+                    const unsigned  off = ((unsigned)pbSrc[1] << 4) | (*pbSrc >> 4);
+                    const int       cb = ((*pbSrc >> 2) & 3) + 3;
+
+                    pbSrc += 2;
+                    if (off > OBJPAGELEN - cbDst)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    cbDst -= cb;
+                    if (cbDst < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    kLdrModLXMemCopyW(pbDst, pbDst - off, cb);
+                    pbDst += cb;
+                }
+                break;
+            }
+
+
+            /*
+             *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+             *  type  |        |  |              |  |                                |
+             *        ----------  ----------------  ----------------------------------
+             *           cb1            cb2                      offset                <cb1 bytes of data>
+             *
+             * Three bytes layed out as described above, followed by cb1 bytes of data to be copied.
+             * The cb2 and offset describes an amount of data to be copied from the expanded
+             * data relative to the current position.
+             *
+             * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
+             */
+            case 3:
+            {
+                cbSrc -= 3;
+                if (cbSrc < 0)
+                    return KLDR_ERR_LX_BAD_ITERDATA2;
+                else
+                {
+                    const int       cb1 = (*pbSrc >> 2) & 0xf;
+                    const int       cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6);
+                    const unsigned  off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4);
+
+                    pbSrc += 3;
+                    cbSrc -= cb1;
+                    if (cbSrc < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    cbDst -= cb1;
+                    if (cbDst < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    kHlpMemCopy(pbDst, pbSrc, cb1);
+                    pbDst += cb1;
+                    pbSrc += cb1;
+
+                    if (off > OBJPAGELEN - cbDst)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    cbDst -= cb2;
+                    if (cbDst < 0)
+                        return KLDR_ERR_LX_BAD_ITERDATA2;
+                    kLdrModLXMemCopyW(pbDst, pbDst - off, cb2);
+                    pbDst += cb2;
+                }
+                break;
+            }
+        } /* type switch. */
+    } /* unpack loop */
+
+l_endloop:
+
+
+    /*
+     * Zero remainder of the page.
+     */
+    if (cbDst > 0)
+        kHlpMemSet(pbDst, 0, cbDst);
+
+    return 0;
+}
+
+
+/**
+ * Special memcpy employed by the iterdata2 algorithm.
+ *
+ * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this
+ * has if src is very close to the destination.
+ *
+ * @param   pbDst   Destination pointer.
+ * @param   pbSrc   Source pointer. Will always be <= pbDst.
+ * @param   cb      Amount of data to be copied.
+ * @remark  This assumes that unaligned word and dword access is fine.
+ */
+static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb)
+{
+    switch (pbDst - pbSrc)
+    {
+        case 0:
+        case 1:
+        case 2:
+        case 3:
+            /* 16-bit copy (unaligned) */
+            if (cb & 1)
+                *pbDst++ = *pbSrc++;
+            for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2)
+                *(KU16 *)pbDst = *(const KU16 *)pbSrc;
+            break;
+
+        default:
+            /* 32-bit copy (unaligned) */
+            if (cb & 1)
+                *pbDst++ = *pbSrc++;
+            if (cb & 2)
+            {
+                *(KU16 *)pbDst = *(const KU16 *)pbSrc;
+                pbDst += 2;
+                pbSrc += 2;
+            }
+            for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4)
+                *(KU32 *)pbDst = *(const KU32 *)pbSrc;
+            break;
+    }
+}
+
+
+/**
+ * Unprotects or protects the specified image mapping.
+ *
+ * @returns 0 on success.
+ * @returns non-zero kLdr or OS status code on failure.
+ *
+ * @param   pModLX  The LX module interpreter instance.
+ * @param   pvBits  The mapping to protect.
+ * @param   UnprotectOrProtect  If 1 unprotect (i.e. make all writable), otherwise
+ *          protect according to the object table.
+ */
+static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect)
+{
+    KU32 i;
+    PKLDRMOD pMod = pModLX->pMod;
+
+    /*
+     * Change object protection.
+     */
+    for (i = 0; i < pMod->cSegments; i++)
+    {
+        int rc;
+        void *pv;
+        KPROT enmProt;
+
+        /* calc new protection. */
+        enmProt = pMod->aSegments[i].enmProt;
+        if (fUnprotectOrProtect)
+        {
+            switch (enmProt)
+            {
+                case KPROT_NOACCESS:
+                case KPROT_READONLY:
+                case KPROT_READWRITE:
+                case KPROT_WRITECOPY:
+                    enmProt = KPROT_READWRITE;
+                    break;
+                case KPROT_EXECUTE:
+                case KPROT_EXECUTE_READ:
+                case KPROT_EXECUTE_READWRITE:
+                case KPROT_EXECUTE_WRITECOPY:
+                    enmProt = KPROT_EXECUTE_READWRITE;
+                    break;
+                default:
+                    KLDRMODLX_ASSERT(!"bad enmProt");
+                    return -1;
+            }
+        }
+        else
+        {
+            /* copy on write -> normal write. */
+            if (enmProt == KPROT_EXECUTE_WRITECOPY)
+                enmProt = KPROT_EXECUTE_READWRITE;
+            else if (enmProt == KPROT_WRITECOPY)
+                enmProt = KPROT_READWRITE;
+        }
+
+
+        /* calc the address and set page protection. */
+        pv = (KU8 *)pvBits + pMod->aSegments[i].RVA;
+
+        rc = kHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt);
+        if (rc)
+            break;
+
+        /** @todo the gap page should be marked NOACCESS! */
+    }
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModUnmap */
+static int kldrModLXUnmap(PKLDRMOD pMod)
+{
+    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
+    KU32        i;
+    int         rc;
+
+    /*
+     * Mapped?
+     */
+    if (!pModLX->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Free the mapping and update the segments.
+     */
+    rc = kHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
+    KLDRMODLX_ASSERT(!rc);
+    pModLX->pvMapping = NULL;
+
+    for (i = 0; i < pMod->cSegments; i++)
+        pMod->aSegments[i].MapAddress = 0;
+
+    return rc;
+}
+
+
+/** @copydoc kLdrModAllocTLS */
+static int kldrModLXAllocTLS(PKLDRMOD pMod)
+{
+    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
+
+    /* no tls, just do the error checking. */
+    if (!pModLX->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+    return 0;
+}
+
+
+/** @copydoc kLdrModFreeTLS */
+static void kldrModLXFreeTLS(PKLDRMOD pMod)
+{
+    /* no tls. */
+}
+
+
+/** @copydoc kLdrModReload */
+static int kldrModLXReload(PKLDRMOD pMod)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    int rc, rc2;
+
+    /*
+     * Mapped?
+     */
+    if (!pModLX->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Before doing anything we'll have to make all pages writable.
+     */
+    rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
+    if (rc)
+        return rc;
+
+    /*
+     * Load the bits again.
+     */
+    rc = kldrModLXDoLoadBits(pModLX, (void *)pModLX->pvMapping);
+
+    /*
+     * Restore protection.
+     */
+    rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
+    if (!rc && rc2)
+        rc = rc2;
+    return rc;
+}
+
+
+/** @copydoc kLdrModFixupMapping */
+static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    int rc, rc2;
+
+    /*
+     * Mapped?
+     */
+    if (!pModLX->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Before doing anything we'll have to make all pages writable.
+     */
+    rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
+    if (rc)
+        return rc;
+
+    /*
+     * Apply fixups and resolve imports.
+     */
+    rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (KUPTR)pModLX->pvMapping,
+                               pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
+
+    /*
+     * Restore protection.
+     */
+    rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
+    if (!rc && rc2)
+        rc = rc2;
+    return rc;
+}
+
+
+/** @copydoc kLdrModCallInit */
+static int kldrModLXCallInit(PKLDRMOD pMod, KUPTR uHandle)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    int rc;
+
+    /*
+     * Mapped?
+     */
+    if (!pModLX->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Do TLS callbacks first and then call the init/term function if it's a DLL.
+     */
+    if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
+        rc = kldrModLXDoCallDLL(pModLX, 0 /* attach */, uHandle);
+    else
+        rc = 0;
+    return rc;
+}
+
+
+/**
+ * Call the DLL entrypoint.
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_MODULE_INIT_FAILED  or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
+ * @param   pModLX          The LX module interpreter instance.
+ * @param   uOp             The operation (DLL_*).
+ * @param   uHandle         The module handle to present.
+ */
+static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, KUPTR uHandle)
+{
+    int rc;
+
+    /*
+     * If no entrypoint there isn't anything to be done.
+     */
+    if (    !pModLX->Hdr.e32_startobj
+        ||  pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
+        return 0;
+
+    /*
+     * Invoke the entrypoint and convert the boolean result to a kLdr status code.
+     */
+    rc = kldrModLXDoCall((KUPTR)pModLX->pvMapping
+                         + (KUPTR)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
+                         + pModLX->Hdr.e32_eip,
+                         uHandle, uOp, NULL);
+    if (rc)
+        rc = 0;
+    else if (uOp == 0 /* attach */)
+        rc = KLDR_ERR_MODULE_INIT_FAILED;
+    else /* detach: ignore failures */
+        rc = 0;
+    return rc;
+}
+
+
+/**
+ * Do a 3 parameter callback.
+ *
+ * @returns 32-bit callback return.
+ * @param   uEntrypoint     The address of the function to be called.
+ * @param   uHandle         The first argument, the module handle.
+ * @param   uOp             The second argumnet, the reason we're calling.
+ * @param   pvReserved      The third argument, reserved argument. (figure this one out)
+ */
+static KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved)
+{
+#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
+    KI32 rc;
+/** @todo try/except */
+
+    /*
+     * Paranoia.
+     */
+# ifdef __GNUC__
+    __asm__ __volatile__(
+        "pushl  %2\n\t"
+        "pushl  %1\n\t"
+        "pushl  %0\n\t"
+        "lea   12(%%esp), %2\n\t"
+        "call  *%3\n\t"
+        "movl   %2, %%esp\n\t"
+        : "=a" (rc)
+        : "d" (uOp),
+          "S" (0),
+          "c" (uEntrypoint),
+          "0" (uHandle));
+# elif defined(_MSC_VER)
+    __asm {
+        mov     eax, [uHandle]
+        mov     edx, [uOp]
+        mov     ecx, 0
+        mov     ebx, [uEntrypoint]
+        push    edi
+        mov     edi, esp
+        push    ecx
+        push    edx
+        push    eax
+        call    ebx
+        mov     esp, edi
+        pop     edi
+        mov     [rc], eax
+    }
+# else
+#  error "port me!"
+# endif
+    return rc;
+
+#else
+    return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE;
+#endif
+}
+
+
+/** @copydoc kLdrModCallTerm */
+static int kldrModLXCallTerm(PKLDRMOD pMod, KUPTR uHandle)
+{
+    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
+
+    /*
+     * Mapped?
+     */
+    if (!pModLX->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Do the call.
+     */
+    if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
+        kldrModLXDoCallDLL(pModLX, 1 /* detach */, uHandle);
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModCallThread */
+static int kldrModLXCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
+{
+    /* no thread attach/detach callout. */
+    return 0;
+}
+
+
+/** @copydoc kLdrModSize */
+static KLDRADDR kldrModLXSize(PKLDRMOD pMod)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    return pModLX->cbMapped;
+}
+
+
+/** @copydoc kLdrModGetBits */
+static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODLX  pModLX = (PKLDRMODLX)pMod->pvData;
+    int         rc;
+
+    /*
+     * Load the image bits.
+     */
+    rc = kldrModLXDoLoadBits(pModLX, pvBits);
+    if (rc)
+        return rc;
+
+    /*
+     * Perform relocations.
+     */
+    return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
+
+}
+
+
+/** @copydoc kLdrModRelocateBits */
+static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                                 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
+    KU32 iSeg;
+    int rc;
+
+    /*
+     * Do we need to to *anything*?
+     */
+    if (    NewBaseAddress == OldBaseAddress
+        &&  NewBaseAddress == pModLX->paObjs[0].o32_base
+        &&  !pModLX->Hdr.e32_impmodcnt)
+        return 0;
+
+    /*
+     * Load the fixup section.
+     */
+    if (!pModLX->pbFixupSection)
+    {
+        rc = kldrModLXDoLoadFixupSection(pModLX);
+        if (rc)
+            return rc;
+    }
+
+    /*
+     * Iterate the segments.
+     */
+    for (iSeg = 0; iSeg < pModLX->Hdr.e32_objcnt; iSeg++)
+    {
+        const struct o32_obj * const pObj = &pModLX->paObjs[iSeg];
+        KLDRADDR        PageAddress = NewBaseAddress + pModLX->pMod->aSegments[iSeg].RVA;
+        KU32            iPage;
+        KU8            *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[iSeg].RVA;
+
+        /*
+         * Iterate the page map pages.
+         */
+        for (iPage = 0, rc = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN, PageAddress += OBJPAGELEN)
+        {
+            const KU8 * const   pbFixupRecEnd = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap];
+            const KU8          *pb            = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap - 1];
+            KLDRADDR            uValue;
+            int                 iSelector;
+            KU32                fKind;
+
+            /* sanity */
+            if (pbFixupRecEnd < pb)
+                return KLDR_ERR_BAD_FIXUP;
+            if (pbFixupRecEnd - 1 > pModLX->pbFixupSectionLast)
+                return KLDR_ERR_BAD_FIXUP;
+            if (pb < pModLX->pbFixupSection)
+                return KLDR_ERR_BAD_FIXUP;
+
+            /*
+             * Iterate the fixup record.
+             */
+            while (pb < pbFixupRecEnd)
+            {
+                union _rel
+                {
+                    const KU8 *             pb;
+                    const struct r32_rlc   *prlc;
+                } u;
+
+                u.pb = pb;
+                pb += 3 + (u.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */
+
+                /*
+                 * Figure out the target.
+                 */
+                switch (u.prlc->nr_flags & NRRTYP)
+                {
+                    /*
+                     * Internal fixup.
+                     */
+                    case NRRINT:
+                    {
+                        KU16 iTrgObject;
+                        KU32 offTrgObject;
+
+                        /* the object */
+                        if (u.prlc->nr_flags & NR16OBJMOD)
+                        {
+                            iTrgObject = *(const KU16 *)pb;
+                            pb += 2;
+                        }
+                        else
+                            iTrgObject = *pb++;
+                        iTrgObject--;
+                        if (iTrgObject >= pModLX->Hdr.e32_objcnt)
+                            return KLDR_ERR_BAD_FIXUP;
+
+                        /* the target */
+                        if ((u.prlc->nr_stype & NRSRCMASK) != NRSSEG)
+                        {
+                            if (u.prlc->nr_flags & NR32BITOFF)
+                            {
+                                offTrgObject = *(const KU32 *)pb;
+                                pb += 4;
+                            }
+                            else
+                            {
+                                offTrgObject = *(const KU16 *)pb;
+                                pb += 2;
+                            }
+
+                            /* calculate the symbol info. */
+                            uValue = offTrgObject + NewBaseAddress + pMod->aSegments[iTrgObject].RVA;
+                        }
+                        else
+                            uValue = NewBaseAddress + pMod->aSegments[iTrgObject].RVA;
+                        if (    (u.prlc->nr_stype & NRALIAS)
+                            ||  (pMod->aSegments[iTrgObject].fFlags & KLDRSEG_FLAG_16BIT))
+                            iSelector = pMod->aSegments[iTrgObject].Sel16bit;
+                        else
+                            iSelector = pMod->aSegments[iTrgObject].SelFlat;
+                        fKind = 0;
+                        break;
+                    }
+
+                    /*
+                     * Import by symbol ordinal.
+                     */
+                    case NRRORD:
+                    {
+                        KU16 iModule;
+                        KU32 iSymbol;
+
+                        /* the module ordinal */
+                        if (u.prlc->nr_flags & NR16OBJMOD)
+                        {
+                            iModule = *(const KU16 *)pb;
+                            pb += 2;
+                        }
+                        else
+                            iModule = *pb++;
+                        iModule--;
+                        if (iModule >= pModLX->Hdr.e32_impmodcnt)
+                            return KLDR_ERR_BAD_FIXUP;
+#if 1
+                        if (u.prlc->nr_flags & NRICHAIN)
+                            return KLDR_ERR_BAD_FIXUP;
+#endif
+
+                        /* . */
+                        if (u.prlc->nr_flags & NR32BITOFF)
+                        {
+                            iSymbol = *(const KU32 *)pb;
+                            pb += 4;
+                        }
+                        else if (!(u.prlc->nr_flags & NR8BITORD))
+                        {
+                            iSymbol = *(const KU16 *)pb;
+                            pb += 2;
+                        }
+                        else
+                            iSymbol = *pb++;
+
+                        /* resolve it. */
+                        rc = pfnGetImport(pMod, iModule, iSymbol, NULL, 0, NULL, &uValue, &fKind, pvUser);
+                        if (rc)
+                            return rc;
+                        iSelector = -1;
+                        break;
+                    }
+
+                    /*
+                     * Import by symbol name.
+                     */
+                    case NRRNAM:
+                    {
+                        KU32 iModule;
+                        KU16 offSymbol;
+                        const KU8 *pbSymbol;
+
+                        /* the module ordinal */
+                        if (u.prlc->nr_flags & NR16OBJMOD)
+                        {
+                            iModule = *(const KU16 *)pb;
+                            pb += 2;
+                        }
+                        else
+                            iModule = *pb++;
+                        iModule--;
+                        if (iModule >= pModLX->Hdr.e32_impmodcnt)
+                            return KLDR_ERR_BAD_FIXUP;
+#if 1
+                        if (u.prlc->nr_flags & NRICHAIN)
+                            return KLDR_ERR_BAD_FIXUP;
+#endif
+
+                        /* . */
+                        if (u.prlc->nr_flags & NR32BITOFF)
+                        {
+                            offSymbol = *(const KU32 *)pb;
+                            pb += 4;
+                        }
+                        else if (!(u.prlc->nr_flags & NR8BITORD))
+                        {
+                            offSymbol = *(const KU16 *)pb;
+                            pb += 2;
+                        }
+                        else
+                            offSymbol = *pb++;
+                        pbSymbol = pModLX->pbImportProcs + offSymbol;
+                        if (    pbSymbol < pModLX->pbImportProcs
+                            ||  pbSymbol > pModLX->pbFixupSectionLast)
+                            return KLDR_ERR_BAD_FIXUP;
+
+                        /* resolve it. */
+                        rc = pfnGetImport(pMod, iModule, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pbSymbol + 1, *pbSymbol, NULL,
+                                          &uValue, &fKind, pvUser);
+                        if (rc)
+                            return rc;
+                        iSelector = -1;
+                        break;
+                    }
+
+                    case NRRENT:
+                        KLDRMODLX_ASSERT(!"NRRENT");
+                    default:
+                        break;
+                }
+
+                /* addend */
+                if (u.prlc->nr_flags & NRADD)
+                {
+                    if (u.prlc->nr_flags & NR32BITADD)
+                    {
+                        uValue += *(const KU32 *)pb;
+                        pb += 4;
+                    }
+                    else
+                    {
+                        uValue += *(const KU16 *)pb;
+                        pb += 2;
+                    }
+                }
+
+
+                /*
+                 * Deal with the 'source' (i.e. the place that should be modified - very logical).
+                 */
+                if (!(u.prlc->nr_stype & NRCHAIN))
+                {
+                    int off = u.prlc->r32_soff;
+
+                    /* common / simple */
+                    if (    (u.prlc->nr_stype & NRSRCMASK) == NROFF32
+                        &&  off >= 0
+                        &&  off <= OBJPAGELEN - 4)
+                        *(KU32 *)&pbPage[off] = uValue;
+                    else if (    (u.prlc->nr_stype & NRSRCMASK) == NRSOFF32
+                            &&  off >= 0
+                            &&  off <= OBJPAGELEN - 4)
+                        *(KU32 *)&pbPage[off] = uValue - (PageAddress + off + 4);
+                    else
+                    {
+                        /* generic */
+                        rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
+                        if (rc)
+                            return rc;
+                    }
+                }
+                else if (!(u.prlc->nr_flags & NRICHAIN))
+                {
+                    const KI16 *poffSrc = (const KI16 *)pb;
+                    KU8 c = u.pb[2];
+
+                    /* common / simple */
+                    if ((u.prlc->nr_stype & NRSRCMASK) == NROFF32)
+                    {
+                        while (c-- > 0)
+                        {
+                            int off = *poffSrc++;
+                            if (off >= 0 && off <= OBJPAGELEN - 4)
+                                *(KU32 *)&pbPage[off] = uValue;
+                            else
+                            {
+                                rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
+                                if (rc)
+                                    return rc;
+                            }
+                        }
+                    }
+                    else if ((u.prlc->nr_stype & NRSRCMASK) == NRSOFF32)
+                    {
+                        while (c-- > 0)
+                        {
+                            int off = *poffSrc++;
+                            if (off >= 0 && off <= OBJPAGELEN - 4)
+                                *(KU32 *)&pbPage[off] = uValue - (PageAddress + off + 4);
+                            else
+                            {
+                                rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind);
+                                if (rc)
+                                    return rc;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        while (c-- > 0)
+                        {
+                            rc = kldrModLXDoReloc(pbPage, *poffSrc++, PageAddress, u.prlc, iSelector, uValue, fKind);
+                            if (rc)
+                                return rc;
+                        }
+                    }
+                    pb = (const KU8 *)poffSrc;
+                }
+                else
+                {
+                    /* This is a pain because it will require virgin pages on a relocation. */
+                    KLDRMODLX_ASSERT(!"NRICHAIN");
+                    return KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+/**
+ * Applies the relocation to one 'source' in a page.
+ *
+ * This takes care of the more esotic case while the common cases
+ * are dealt with seperately.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pbPage      The page in which to apply the fixup.
+ * @param   off         Page relative offset of where to apply the offset.
+ * @param   uValue      The target value.
+ * @param   fKind       The target kind.
+ */
+static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc,
+                            int iSelector, KLDRADDR uValue, KU32 fKind)
+{
+#pragma pack(1) /* just to be sure */
+    union
+    {
+        KU8         ab[6];
+        KU32        off32;
+        KU16        off16;
+        KU8         off8;
+        struct
+        {
+            KU16    off;
+            KU16    Sel;
+        }           Far16;
+        struct
+        {
+            KU32    off;
+            KU16    Sel;
+        }           Far32;
+    }               uData;
+#pragma pack()
+    const KU8      *pbSrc;
+    KU8            *pbDst;
+    KU8             cb;
+
+    /*
+     * Compose the fixup data.
+     */
+    switch (prlc->nr_stype & NRSRCMASK)
+    {
+        case NRSBYT:
+            uData.off8 = (KU8)uValue;
+            cb = 1;
+            break;
+        case NRSSEG:
+            if (iSelector == -1)
+            {
+                /* fixme */
+            }
+            uData.off16 = iSelector;
+            cb = 2;
+            break;
+        case NRSPTR:
+            if (iSelector == -1)
+            {
+                /* fixme */
+            }
+            uData.Far16.off = (KU16)uValue;
+            uData.Far16.Sel = iSelector;
+            cb = 4;
+            break;
+        case NRSOFF:
+            uData.off16 = (KU16)uValue;
+            cb = 2;
+            break;
+        case NRPTR48:
+            if (iSelector == -1)
+            {
+                /* fixme */
+            }
+            uData.Far32.off = (KU32)uValue;
+            uData.Far32.Sel = iSelector;
+            cb = 6;
+            break;
+        case NROFF32:
+            uData.off32 = (KU32)uValue;
+            cb = 4;
+            break;
+        case NRSOFF32:
+            uData.off32 = (KU32)uValue - (PageAddress + off + 4);
+            cb = 4;
+            break;
+        default:
+            return KLDR_ERR_LX_BAD_FIXUP_SECTION; /** @todo fix error, add more checks! */
+    }
+
+    /*
+     * Apply it. This is sloooow...
+     */
+    pbSrc = &uData.ab[0];
+    pbDst = pbPage + off;
+    while (cb-- > 0)
+    {
+        if (off > OBJPAGELEN)
+            break;
+        if (off >= 0)
+            *pbDst = *pbSrc;
+        pbSrc++;
+        pbDst++;
+    }
+
+    return 0;
+}
+
+
+/**
+ * The LX module interpreter method table.
+ */
+KLDRMODOPS g_kLdrModLXOps =
+{
+    "LX",
+    NULL,
+    kldrModLXCreate,
+    kldrModLXDestroy,
+    kldrModLXQuerySymbol,
+    kldrModLXEnumSymbols,
+    kldrModLXGetImport,
+    kldrModLXNumberOfImports,
+    NULL /* can execute one is optional */,
+    kldrModLXGetStackInfo,
+    kldrModLXQueryMainEntrypoint,
+    NULL /* fixme */,
+    NULL /* fixme */,
+    kldrModLXEnumDbgInfo,
+    kldrModLXHasDbgInfo,
+    kldrModLXMap,
+    kldrModLXUnmap,
+    kldrModLXAllocTLS,
+    kldrModLXFreeTLS,
+    kldrModLXReload,
+    kldrModLXFixupMapping,
+    kldrModLXCallInit,
+    kldrModLXCallTerm,
+    kldrModLXCallThread,
+    kldrModLXSize,
+    kldrModLXGetBits,
+    kldrModLXRelocateBits,
+    NULL /* fixme: pfnMostlyDone */,
+    42 /* the end */
+};
+
Index: /trunk/kLdr/kLdrModMachO.c
===================================================================
--- /trunk/kLdr/kLdrModMachO.c	(revision 2)
+++ /trunk/kLdr/kLdrModMachO.c	(revision 2)
@@ -0,0 +1,2410 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Module Interpreter for the MACH-O format.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+#include <k/kLdrFmts/mach-o.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRMODMACHO_STRICT
+ * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */
+#define KLDRMODMACHO_STRICT 1
+
+/** @def KLDRMODMACHO_ASSERT
+ * Assert that an expression is true when KLDR_STRICT is defined.
+ */
+#ifdef KLDRMODMACHO_STRICT
+# define KLDRMODMACHO_ASSERT(expr)  kHlpAssert(expr)
+#else
+# define KLDRMODMACHO_ASSERT(expr)  do {} while (0)
+#endif
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Mach-O section details.
+ */
+typedef struct KLDRMODMACHOSECT
+{
+    /** The size of the section (in bytes). */
+    KLDRSIZE                cb;
+    /** The link address of this section. */
+    KLDRADDR                LinkAddress;
+    /** The RVA of this section. */
+    KLDRADDR                RVA;
+    /** The file offset of this section.
+     * This is -1 if the section doesn't have a file backing. */
+    KLDRFOFF                offFile;
+    /** The number of fixups. */
+    KU32                    cFixups;
+    /** The array of fixups. (lazy loaded) */
+    macho_relocation_info_t *paFixups;
+    /** The file offset of the fixups for this section.
+     * This is -1 if the section doesn't have any fixups. */
+    KLDRFOFF                offFixups;
+    /** Mach-O section flags. */
+    KU32                    fFlags;
+    /** kLdr segment index. */
+    KU32                    iSegment;
+    /** Pointer to the Mach-O section structure. */
+    void                   *pvMachoSection;
+} KLDRMODMACHOSECT, *PKLDRMODMACHOSECT;
+
+/**
+ * Extra per-segment info.
+ *
+ * This is corresponds to a kLdr segment, not a Mach-O segment!
+ */
+typedef struct KLDRMODMACHOSEG
+{
+    /** The number of sections in the segment. */
+    KU32                    cSections;
+    /** Pointer to the sections belonging to this segment.
+     * The array resides in the big memory chunk allocated for
+     * the module handle, so it doesn't need freeing. */
+    PKLDRMODMACHOSECT       paSections;
+
+} KLDRMODMACHOSEG, *PKLDRMODMACHOSEG;
+
+/**
+ * Instance data for the Mach-O MH_OBJECT module interpreter.
+ * @todo interpret the other MH_* formats.
+ */
+typedef struct KLDRMODMACHO
+{
+    /** Pointer to the module. (Follows the section table.) */
+    PKLDRMOD                pMod;
+    /** Pointer to the RDR file mapping of the raw file bits. NULL if not mapped. */
+    const void             *pvBits;
+    /** Pointer to the user mapping. */
+    void                   *pvMapping;
+
+    /** The link address. */
+    KLDRADDR                LinkAddress;
+    /** The size of the mapped image. */
+    KLDRADDR                cbImage;
+    /** When set the sections in the load command segments must be used when
+     * mapping or loading the image. */
+    int                     fMapUsingLoadCommandSections;
+
+    /** Pointer to the load commands. (endian converted) */
+    KU8                    *pbLoadCommands;
+    /** The Mach-O header. (endian converted)
+     * @remark The reserved field is only valid for real 64-bit headers. */
+    mach_header_64_t        Hdr;
+
+    /** The offset of the symbol table. */
+    KLDRFOFF                offSymbols;
+    /** The number of symbols. */
+    KU32                    cSymbols;
+    /** The pointer to the loaded symbol table. */
+    void                   *pvaSymbols;
+    /** The offset of the string table. */
+    KLDRFOFF                offStrings;
+    /** The size of the of the string table. */
+    KU32                    cchStrings;
+    /** Pointer to the loaded string table. */
+    char                   *pchStrings;
+
+    /** The number of sections. */
+    KU32                    cSections;
+    /** Pointer to the section array running in parallel to the Mach-O one. */
+    PKLDRMODMACHOSECT       paSections;
+
+    /** Array of segments parallel to the one in KLDRMOD. */
+    KLDRMODMACHOSEG         aSegments[1];
+} KLDRMODMACHO, *PKLDRMODMACHO;
+
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+#if 0
+static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits);
+#endif
+static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                                    PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+
+static int  kldrModMachODoCreate(PKRDR pRdr, PKLDRMODMACHO *ppMod);
+static int  kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr,
+                                             KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool);
+static int  kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool);
+static int  kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress);
+
+/*static int  kldrModMachOLoadLoadCommands(PKLDRMODMACHO pModMachO);*/
+static int  kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO);
+static int  kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups);
+static int  kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO);
+
+static int  kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings,
+                                           KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol,
+                                           KSIZE cchSymbol, PKLDRADDR puValue, KU32 *pfKind);
+static int  kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
+                                           const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
+                                           KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser);
+static int  kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+static int  kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress);
+static int  kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
+                                                 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress);
+
+/*static int  kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
+static int  kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);*/
+
+
+/**
+ * Create a loader module instance interpreting the executable image found
+ * in the specified file provider instance.
+ *
+ * @returns 0 on success and *ppMod pointing to a module instance.
+ *          On failure, a non-zero OS specific error code is returned.
+ * @param   pOps            Pointer to the registered method table.
+ * @param   pRdr            The file provider instance to use.
+ * @param   offNewHdr       The offset of the new header in MZ files. -1 if not found.
+ * @param   ppMod           Where to store the module instance pointer.
+ */
+static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
+{
+    PKLDRMODMACHO pModMachO;
+    int rc;
+
+    /*
+     * Create the instance data and do a minimal header validation.
+     */
+    rc = kldrModMachODoCreate(pRdr, &pModMachO);
+    if (!rc)
+    {
+        pModMachO->pMod->pOps = pOps;
+        pModMachO->pMod->u32Magic = KLDRMOD_MAGIC;
+        *ppMod = pModMachO->pMod;
+        return 0;
+    }
+    if (pModMachO)
+    {
+        kHlpFree(pModMachO->pbLoadCommands);
+        kHlpFree(pModMachO);
+    }
+    return rc;
+}
+
+
+/**
+ * Separate function for reading creating the PE module instance to
+ * simplify cleanup on failure.
+ */
+static int kldrModMachODoCreate(PKRDR pRdr, PKLDRMODMACHO *ppModMachO)
+{
+    union
+    {
+        mach_header_32_t    Hdr32;
+        mach_header_64_t    Hdr64;
+    } s;
+    PKLDRMODMACHO pModMachO;
+    PKLDRMOD pMod;
+    KU8 *pbLoadCommands;
+    KU32 cSegments;
+    KU32 cSections;
+    KU32 cbStringPool;
+    KSIZE cchFilename;
+    KSIZE cb;
+    int rc;
+    *ppModMachO = NULL;
+
+    /*
+     * Read the Mach-O header.
+     */
+    rc = kRdrRead(pRdr, &s, sizeof(s), 0);
+    if (rc)
+        return rc;
+    if (s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
+    {
+        if (    s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
+            ||  s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE)
+            return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED;
+        if (s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE)
+            return KLDR_ERR_MACHO_64BIT_NOT_SUPPORTED;
+        return KLDR_ERR_UNKNOWN_FORMAT;
+    }
+
+    /* sanity checks. */
+    if (    s.Hdr32.sizeofcmds > kRdrSize(pRdr) - sizeof(mach_header_32_t)
+        ||  s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds
+        ||  (s.Hdr32.flags & ~MH_VALID_FLAGS))
+        return KLDR_ERR_MACHO_BAD_HEADER;
+    switch (s.Hdr32.cputype)
+    {
+        case CPU_TYPE_X86:
+        case CPU_TYPE_X86_64:
+            break;
+        default:
+            return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
+    }
+    if (s.Hdr32.filetype != MH_OBJECT)
+        return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
+
+    /*
+     * Read and pre-parse the load commands to figure out how many segments we'll be needing.
+     */
+    pbLoadCommands = kHlpAlloc(s.Hdr32.sizeofcmds);
+    if (!pbLoadCommands)
+        return KERR_NO_MEMORY;
+    rc = kRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds,
+                        s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
+                     || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE
+                     ? sizeof(mach_header_32_t) : sizeof(mach_header_64_t));
+    if (!rc)
+        rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, &cSegments, &cSections, &cbStringPool);
+    if (rc)
+    {
+        kHlpFree(pbLoadCommands);
+        return rc;
+    }
+
+
+    /*
+     * Calc the instance size, allocate and initialize it.
+     */
+    cchFilename = kHlpStrLen(kRdrName(pRdr));
+    cb = K_ALIGN_Z(  K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
+                      + sizeof(KLDRMODMACHOSECT) * cSections, 16)
+       + K_OFFSETOF(KLDRMOD, aSegments[cSegments])
+       + cchFilename + 1
+       + cbStringPool;
+    pModMachO = (PKLDRMODMACHO)kHlpAlloc(cb);
+    if (!pModMachO)
+        return KERR_NO_MEMORY;
+    *ppModMachO = pModMachO;
+    pModMachO->pbLoadCommands = pbLoadCommands;
+
+    /* KLDRMOD */
+    pMod = (PKLDRMOD)((KU8 *)pModMachO + K_ALIGN_Z(  K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments])
+                                                      + sizeof(KLDRMODMACHOSECT) * cSections, 16));
+    pMod->pvData = pModMachO;
+    pMod->pRdr = pRdr;
+    pMod->pOps = NULL;      /* set upon success. */
+    pMod->cSegments = cSegments;
+    pMod->cchFilename = cchFilename;
+    pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
+    kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1);
+    pMod->pszName = kHlpGetFilename(pMod->pszFilename);
+    pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
+    switch (s.Hdr32.cputype)
+    {
+        case CPU_TYPE_X86:
+            pMod->enmArch = KCPUARCH_X86_32;
+            pMod->enmEndian = KLDRENDIAN_LITTLE;
+            switch (s.Hdr32.cpusubtype)
+            {
+                case CPU_SUBTYPE_I386_ALL:          pMod->enmCpu = KCPU_X86_32_BLEND; break;
+                /*case CPU_SUBTYPE_386: ^^           pMod->enmCpu = KCPU_I386; break;*/
+                case CPU_SUBTYPE_486:               pMod->enmCpu = KCPU_I486; break;
+                case CPU_SUBTYPE_486SX:             pMod->enmCpu = KCPU_I486SX; break;
+                /*case CPU_SUBTYPE_586: vv */
+                case CPU_SUBTYPE_PENT:              pMod->enmCpu = KCPU_I586; break;
+                case CPU_SUBTYPE_PENTPRO:
+                case CPU_SUBTYPE_PENTII_M3:
+                case CPU_SUBTYPE_PENTII_M5:
+                case CPU_SUBTYPE_CELERON:
+                case CPU_SUBTYPE_CELERON_MOBILE:
+                case CPU_SUBTYPE_PENTIUM_3:
+                case CPU_SUBTYPE_PENTIUM_3_M:
+                case CPU_SUBTYPE_PENTIUM_3_XEON:    pMod->enmCpu = KCPU_I686; break;
+                case CPU_SUBTYPE_PENTIUM_M:
+                case CPU_SUBTYPE_PENTIUM_4:
+                case CPU_SUBTYPE_PENTIUM_4_M:
+                case CPU_SUBTYPE_XEON:
+                case CPU_SUBTYPE_XEON_MP:           pMod->enmCpu = KCPU_P4; break;
+                    break;
+                default:
+                    return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
+            }
+            break;
+
+        case CPU_TYPE_X86_64:
+            pMod->enmArch = KCPUARCH_AMD64;
+            pMod->enmEndian = KLDRENDIAN_LITTLE;
+            switch (s.Hdr32.cpusubtype)
+            {
+                case CPU_SUBTYPE_X86_64_ALL:        pMod->enmCpu = KCPU_AMD64_BLEND; break;
+                default:
+                    return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
+            }
+            break;
+
+        default:
+            return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE;
+    }
+
+    pMod->enmFmt = KLDRFMT_MACHO;
+    switch (s.Hdr32.filetype)
+    {
+        case MH_OBJECT:
+            pMod->enmType = KLDRTYPE_OBJECT;
+            break;
+        default:
+            return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE;
+    }
+    pMod->u32Magic = 0;     /* set upon success. */
+
+    /* KLDRMODMACHO */
+    pModMachO->pMod = pMod;
+    pModMachO->pvBits = NULL;
+    pModMachO->pvMapping = NULL;
+    pModMachO->Hdr = s.Hdr64;
+    if (    s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE
+        ||  s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE)
+        pModMachO->Hdr.reserved = 0;
+    pModMachO->LinkAddress = 0;
+    pModMachO->cbImage = 0;
+    pModMachO->fMapUsingLoadCommandSections = 0;
+    pModMachO->offSymbols = 0;
+    pModMachO->cSymbols = 0;
+    pModMachO->pvaSymbols = NULL;
+    pModMachO->offStrings = 0;
+    pModMachO->cchStrings = 0;
+    pModMachO->pchStrings = NULL;
+    pModMachO->cSections = cSections;
+    pModMachO->paSections = (PKLDRMODMACHOSECT)&pModMachO->aSegments[pModMachO->pMod->cSegments];
+
+    /*
+     * Setup the KLDRMOD segment array.
+     */
+    rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool);
+    if (rc)
+        return rc;
+
+    /*
+     * We're done.
+     */
+    return 0;
+}
+
+
+/**
+ * Converts, validates and preparses the load commands before we carve
+ * out the module instance.
+ *
+ * The conversion that's preformed is format endian to host endian.
+ * The preparsing has to do with segment counting, section counting and string pool sizing.
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_MACHO_* on failure.
+ * @param   pbLoadCommands  The load commands to parse.
+ * @param   pHdr            The header.
+ * @param   pRdr            The file reader.
+ * @param   pcSegments      Where to store the segment count.
+ * @param   pcSegments      Where to store the section count.
+ * @param   pcbStringPool   Where to store the string pool size.
+ */
+static int  kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr,
+                                             KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool)
+{
+    union
+    {
+        KU8                  *pb;
+        load_command_t       *pLoadCmd;
+        segment_command_32_t *pSeg32;
+        segment_command_64_t *pSeg64;
+        thread_command_t     *pThread;
+        symtab_command_t     *pSymTab;
+        uuid_command_t       *pUuid;
+    } u;
+    const KU64 cbFile = kRdrSize(pRdr);
+    KU32 cSegments = 0;
+    KU32 cSections = 0;
+    KU32 cbStringPool = 0;
+    KU32 cLeft = pHdr->ncmds;
+    KU32 cbLeft = pHdr->sizeofcmds;
+    KU8 *pb = pbLoadCommands;
+    int cSegmentCommands = 0;
+    int cSymbolTabs = 0;
+    int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
+                      || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
+
+    *pcSegments = 0;
+    *pcSections = 0;
+    *pcbStringPool = 0;
+
+    while (cLeft-- > 0)
+    {
+        u.pb = pb;
+
+        /*
+         * Convert and validate command header.
+         */
+        if (cbLeft < sizeof(load_command_t))
+            return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+        if (fConvertEndian)
+        {
+            u.pLoadCmd->cmd = K_E2E_U32(u.pLoadCmd->cmd);
+            u.pLoadCmd->cmdsize = K_E2E_U32(u.pLoadCmd->cmdsize);
+        }
+        if (u.pLoadCmd->cmdsize > cbLeft)
+            return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+        cbLeft -= u.pLoadCmd->cmdsize;
+        pb += u.pLoadCmd->cmdsize;
+
+        /*
+         * Convert endian if needed, parse and validate the command.
+         */
+        switch (u.pLoadCmd->cmd)
+        {
+            case LC_SEGMENT_32:
+            {
+                section_32_t *pSect;
+                section_32_t *pFirstSect;
+                KU32 cSectionsLeft;
+
+                /* convert and verify*/
+                if (u.pLoadCmd->cmdsize < sizeof(segment_command_32_t))
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                if (    pHdr->magic != IMAGE_MACHO32_SIGNATURE_OE
+                    &&  pHdr->magic != IMAGE_MACHO32_SIGNATURE)
+                    return KLDR_ERR_MACHO_BIT_MIX;
+                if (fConvertEndian)
+                {
+                    u.pSeg32->vmaddr   = K_E2E_U32(u.pSeg32->vmaddr);
+                    u.pSeg32->vmsize   = K_E2E_U32(u.pSeg32->vmsize);
+                    u.pSeg32->fileoff  = K_E2E_U32(u.pSeg32->fileoff);
+                    u.pSeg32->filesize = K_E2E_U32(u.pSeg32->filesize);
+                    u.pSeg32->maxprot  = K_E2E_U32(u.pSeg32->maxprot);
+                    u.pSeg32->initprot = K_E2E_U32(u.pSeg32->initprot);
+                    u.pSeg32->nsects   = K_E2E_U32(u.pSeg32->nsects);
+                    u.pSeg32->flags    = K_E2E_U32(u.pSeg32->flags);
+                }
+
+                if (    u.pSeg32->filesize
+                    &&  (   u.pSeg32->fileoff > cbFile
+                         || (KU64)u.pSeg32->fileoff + u.pSeg32->filesize > cbFile))
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                if (!u.pSeg32->filesize && u.pSeg32->fileoff)
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                if (u.pSeg32->vmsize < u.pSeg32->filesize)
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                if ((u.pSeg32->maxprot & u.pSeg32->initprot) != u.pSeg32->initprot)
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                if (u.pSeg32->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                if (u.pSeg32->nsects * sizeof(section_32_t) > u.pLoadCmd->cmdsize - sizeof(segment_command_32_t))
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                if (    pHdr->filetype == MH_OBJECT
+                    &&  cSegmentCommands > 0)
+                    return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
+                cSegmentCommands++;
+
+                /*
+                 * convert, validate and parse the sections.
+                 */
+                cSectionsLeft = u.pSeg32->nsects;
+                pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
+                while (cSectionsLeft-- > 0)
+                {
+                    int fFileBits;
+
+                    if (fConvertEndian)
+                    {
+                        pSect->addr      = K_E2E_U32(pSect->addr);
+                        pSect->size      = K_E2E_U32(pSect->size);
+                        pSect->offset    = K_E2E_U32(pSect->offset);
+                        pSect->align     = K_E2E_U32(pSect->align);
+                        pSect->reloff    = K_E2E_U32(pSect->reloff);
+                        pSect->nreloc    = K_E2E_U32(pSect->nreloc);
+                        pSect->flags     = K_E2E_U32(pSect->flags);
+                        pSect->reserved1 = K_E2E_U32(pSect->reserved1);
+                        pSect->reserved2 = K_E2E_U32(pSect->reserved2);
+                    }
+
+                    /* validate */
+                    switch (pSect->flags & SECTION_TYPE)
+                    {
+                        case S_ZEROFILL:
+                            if (pSect->reserved1 || pSect->reserved2)
+                                return KLDR_ERR_MACHO_BAD_SECTION;
+                            fFileBits = 0;
+                            break;
+                        case S_REGULAR:
+                        case S_CSTRING_LITERALS:
+                        case S_COALESCED:
+                        case S_4BYTE_LITERALS:
+                        case S_8BYTE_LITERALS:
+                        case S_16BYTE_LITERALS:
+                            if (pSect->reserved1 || pSect->reserved2)
+                                return KLDR_ERR_MACHO_BAD_SECTION;
+                            fFileBits = 1;
+                            break;
+
+                        case S_LITERAL_POINTERS:
+                        case S_INTERPOSING:
+                        case S_GB_ZEROFILL:
+                        case S_NON_LAZY_SYMBOL_POINTERS:
+                        case S_LAZY_SYMBOL_POINTERS:
+                        case S_SYMBOL_STUBS:
+                        case S_MOD_INIT_FUNC_POINTERS:
+                        case S_MOD_TERM_FUNC_POINTERS:
+                            return KLDR_ERR_MACHO_UNSUPPORTED_SECTION;
+
+                        default:
+                            return KLDR_ERR_MACHO_UNKNOWN_SECTION;
+                    }
+                    if (pSect->flags & ~(  S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS
+                                         | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE
+                                         | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC
+                                         | S_ATTR_LOC_RELOC | SECTION_TYPE))
+                        return KLDR_ERR_MACHO_BAD_SECTION;
+                    if (    pSect->addr - u.pSeg32->vmaddr > u.pSeg32->vmsize
+                        ||  pSect->addr - u.pSeg32->vmaddr + pSect->size > u.pSeg32->vmsize)
+                        return KLDR_ERR_MACHO_BAD_SECTION;
+                    if (    pSect->align >= 31
+                        ||  (((1 << pSect->align) - 1) & pSect->addr)
+                        ||  (((1 << pSect->align) - 1) & u.pSeg32->vmaddr))
+                        return KLDR_ERR_MACHO_BAD_SECTION;
+                    if (    fFileBits
+                        &&  (   pSect->offset > cbFile
+                             || (KU64)pSect->offset + pSect->size > cbFile))
+                        return KLDR_ERR_MACHO_BAD_SECTION;
+                    if (!fFileBits && pSect->offset)
+                        return KLDR_ERR_MACHO_BAD_SECTION;
+                    if (!pSect->nreloc && pSect->reloff)
+                        return KLDR_ERR_MACHO_BAD_SECTION;
+                    if (    pSect->nreloc
+                        &&  (   pSect->reloff > cbFile
+                             || (KU64)pSect->reloff + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t)) > cbFile)
+                        return KLDR_ERR_MACHO_BAD_SECTION;
+
+
+                    /* count segments and strings */
+                    switch (pHdr->filetype)
+                    {
+                        case MH_OBJECT:
+                        {
+                            cSections++;
+
+                            /* Don't load debug symbols. (test this) */
+                            if (pSect->flags & S_ATTR_DEBUG)
+                                break;
+
+                            /* a new segment? */
+                            if (    !cSegments
+                                ||  kHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
+                            {
+#if 0 /** @todo This  doesn't work because of BSS. */
+                                /* verify that the linker/assembler has ordered sections correctly. */
+                                section_32_t *pCur = (pSect - 2);
+                                while ((KUPTR)pCur >= (KUPTR)pFirstSect)
+                                {
+                                    if (!kHlpStrNComp(pCur->segname, pSect->segname, sizeof(pSect->segname)))
+                                        return KLDR_ERR_MACHO_BAD_SECTION_ORDER;
+                                    pCur--;
+                                }
+#endif
+
+                                /* ok. count it and the string. */
+                                cSegments++;
+                                cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1;
+                            }
+                            break;
+                        }
+
+                        default:
+                            return KERR_INVALID_PARAMETER;
+                    }
+
+                    /* next */
+                    pSect++;
+                }
+                break;
+            }
+
+            /*case LC_SEGMENT_64:
+                 copy 32-bit code
+                break;
+            */
+
+            case LC_SYMTAB:
+            {
+                KSIZE cbSym;
+                if (fConvertEndian)
+                {
+                    u.pSymTab->symoff  = K_E2E_U32(u.pSymTab->symoff);
+                    u.pSymTab->nsyms   = K_E2E_U32(u.pSymTab->nsyms);
+                    u.pSymTab->stroff  = K_E2E_U32(u.pSymTab->stroff);
+                    u.pSymTab->strsize = K_E2E_U32(u.pSymTab->strsize);
+                }
+
+                /* verify */
+                cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE
+                     || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
+                      ? sizeof(macho_nlist_32_t)
+                      : sizeof(macho_nlist_64_t);
+                if (    u.pSymTab->symoff >= cbFile
+                    ||  (KU64)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > cbFile)
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                if (    u.pSymTab->stroff >= cbFile
+                    ||  (KU64)u.pSymTab->stroff + u.pSymTab->strsize > cbFile)
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+
+                /* only one string in objects, please. */
+                cSymbolTabs++;
+                if (    pHdr->filetype == MH_OBJECT
+                    &&  cSymbolTabs != 1)
+                    return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
+                break;
+            }
+
+            case LC_DYSYMTAB:
+                /** @todo deal with this! */
+                break;
+
+            case LC_THREAD:
+            case LC_UNIXTHREAD:
+            {
+                KU32 *pu32 = (KU32 *)(u.pb + sizeof(load_command_t));
+                KU32 cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(KU32);
+                while (cItemsLeft)
+                {
+                    /* convert & verify header items ([0] == flavor, [1] == KU32 count). */
+                    if (cItemsLeft < 2)
+                        return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                    if (fConvertEndian)
+                    {
+                        pu32[0] = K_E2E_U32(pu32[0]);
+                        pu32[1] = K_E2E_U32(pu32[1]);
+                    }
+                    if (pu32[1] + 2 > cItemsLeft)
+                        return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+
+                    /* convert & verify according to flavor. */
+                    switch (pu32[0])
+                    {
+                        /** @todo */
+                        default:
+                            break;
+                    }
+
+                    /* next */
+                    cItemsLeft -= pu32[1] + 2;
+                    pu32 += pu32[1] + 2;
+                }
+                break;
+            }
+
+            case LC_UUID:
+                if (u.pUuid->cmdsize != sizeof(uuid_command_t))
+                    return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+                /** @todo Check anything here need converting? */
+                break;
+
+            case LC_SEGMENT_64:
+            case LC_LOADFVMLIB:
+            case LC_IDFVMLIB:
+            case LC_IDENT:
+            case LC_FVMFILE:
+            case LC_PREPAGE:
+            case LC_LOAD_DYLIB:
+            case LC_ID_DYLIB:
+            case LC_LOAD_DYLINKER:
+            case LC_ID_DYLINKER:
+            case LC_PREBOUND_DYLIB:
+            case LC_ROUTINES:
+            case LC_ROUTINES_64:
+            case LC_SUB_FRAMEWORK:
+            case LC_SUB_UMBRELLA:
+            case LC_SUB_CLIENT:
+            case LC_SUB_LIBRARY:
+            case LC_TWOLEVEL_HINTS:
+            case LC_PREBIND_CKSUM:
+            case LC_LOAD_WEAK_DYLIB:
+            case LC_SYMSEG:
+                return KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND;
+
+            default:
+                return KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND;
+        }
+    }
+
+    /* be strict. */
+    if (cbLeft)
+        return KLDR_ERR_MACHO_BAD_LOAD_COMMAND;
+
+    switch (pHdr->filetype)
+    {
+        case MH_OBJECT:
+            if (!cSegments)
+                return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
+            break;
+    }
+
+    *pcSegments = cSegments;
+    *pcSections = cSections;
+    *pcbStringPool = cbStringPool;
+
+    return 0;
+}
+
+
+/**
+ * Parses the load commands after we've carved out the module instance.
+ *
+ * This fills in the segment table and perhaps some other properties.
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_MACHO_* on failure.
+ * @param   pModMachO       The module.
+ * @param   pbStringPool    The string pool
+ * @param   cbStringPool    The size of the string pool.
+ */
+static int  kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool)
+{
+    union
+    {
+        const KU8                  *pb;
+        const load_command_t       *pLoadCmd;
+        const segment_command_32_t *pSeg32;
+        const segment_command_64_t *pSeg64;
+        const symtab_command_t     *pSymTab;
+    } u;
+    KU32 cLeft = pModMachO->Hdr.ncmds;
+    KU32 cbLeft = pModMachO->Hdr.sizeofcmds;
+    const KU8 *pb = pModMachO->pbLoadCommands;
+    int fFirstSegment = 1;
+    PKLDRSEG pSeg = &pModMachO->pMod->aSegments[0];
+    PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0];
+    PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections;
+    const KU32 cSegments = pModMachO->pMod->cSegments;
+    KU32 i;
+
+    while (cLeft-- > 0)
+    {
+        u.pb = pb;
+        cbLeft -= u.pLoadCmd->cmdsize;
+        pb += u.pLoadCmd->cmdsize;
+
+        /*
+         * Convert endian if needed, parse and validate the command.
+         */
+        switch (u.pLoadCmd->cmd)
+        {
+            case LC_SEGMENT_32:
+            {
+                section_32_t *pSect;
+                section_32_t *pFirstSect;
+                KU32 cSectionsLeft;
+
+                pModMachO->LinkAddress = u.pSeg32->vmaddr;
+
+                /*
+                 * convert, validate and parse the sections.
+                 */
+                cSectionsLeft = u.pSeg32->nsects;
+                pFirstSect = pSect = (section_32_t *)(u.pSeg32 + 1);
+                while (cSectionsLeft-- > 0)
+                {
+                    switch (pModMachO->Hdr.filetype)
+                    {
+                        case MH_OBJECT:
+                        {
+                            /* Section data extract. */
+                            pSectExtra->cb = pSect->size;
+                            pSectExtra->RVA = pSect->addr;
+                            pSectExtra->LinkAddress = pSect->addr;
+                            pSectExtra->offFile = pSect->offset ? pSect->offset : -1;
+                            pSectExtra->cFixups = pSect->nreloc;
+                            pSectExtra->paFixups = NULL;
+                            pSectExtra->offFixups = pSect->nreloc ? pSect->reloff : -1;
+                            pSectExtra->fFlags = pSect->flags;
+                            pSectExtra->iSegment = pSegExtra - &pModMachO->aSegments[0];
+                            pSectExtra->pvMachoSection = pSect;
+
+                            /* Don't load debug symbols. (test this!) */
+                            if (pSect->flags & S_ATTR_DEBUG)
+                            {
+                                pSectExtra++;
+                                /** @todo */
+                                break;
+                            }
+
+                            if (    fFirstSegment
+                                ||  kHlpStrNComp(pSect->segname, (pSect - 1)->segname, sizeof(pSect->segname)))
+                            {
+                                /* close the previous segment */
+                                if (pSegExtra != &pModMachO->aSegments[0])
+                                    pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
+
+                                /* new segment. */
+                                pSeg->pvUser = NULL;
+                                pSeg->pchName = pbStringPool;
+                                pSeg->cchName = (KU32)kHlpStrNLen(&pSect->segname[0], sizeof(pSect->sectname));
+                                kHlpMemCopy(pbStringPool, &pSect->segname[0], pSeg->cchName);
+                                pbStringPool += pSeg->cchName;
+                                *pbStringPool++ = '\0';
+                                pSeg->SelFlat = 0;
+                                pSeg->Sel16bit = 0;
+                                pSeg->fFlags = 0;
+                                pSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */
+                                pSeg->cb = pSect->size;
+                                pSeg->Alignment = (1 << pSect->align);
+                                pSeg->LinkAddress = pSect->addr;
+                                pSeg->offFile = pSect->offset ? pSect->offset : -1;
+                                pSeg->cbFile  = pSect->offset ? pSect->size : -1;
+                                pSeg->RVA = pSect->addr - pModMachO->LinkAddress;
+                                pSeg->cbMapped = 0;
+                                pSeg->MapAddress = 0;
+
+                                pSegExtra->cSections = 0;
+                                pSegExtra->paSections = pSectExtra;
+
+                                pSeg++;
+                                pSegExtra++;
+                                fFirstSegment = 0;
+                            }
+                            else
+                            {
+                                /* update exiting segment */
+                                if (pSeg[-1].Alignment < (1 << pSect->align))
+                                    pSeg[-1].Alignment = (1 << pSect->align);
+                                if (pSect->addr < pSeg[-1].LinkAddress)
+                                    return KLDR_ERR_MACHO_BAD_SECTION; /** @todo move up! */
+
+                                /* If there are file bits, ensure they are in the current flow.
+                                   (yes, we are very very careful here, I know.) */
+                                if (    pSect->offset
+                                    &&  pSeg[-1].cbFile == pSeg[-1].cb)
+                                {
+                                    int fOk = pSeg[-1].offFile + (pSect->addr - pSeg[-1].LinkAddress) == pSect->offset
+                                           && pSect[-1].offset
+                                           && pSeg[-1].offFile + pSeg[-1].cbFile == pSect[-1].offset + pSect[-1].size;
+                                    /* more checks? */
+                                    if (fOk)
+                                        pSeg[-1].cbFile = (KLDRFOFF)(pSect->addr - pSeg[-1].LinkAddress) + pSect->size;
+                                    else
+                                    {
+
+                                        pSeg[-1].cbFile = pSeg[-1].offFile = -1;
+                                        pModMachO->fMapUsingLoadCommandSections = 1;
+                                    }
+                                }
+                                pSeg[-1].cb = pSect->addr - pSeg[-1].LinkAddress + pSect->size;
+
+                                /** @todo update the protection... */
+                            }
+                            pSectExtra++;
+                            break;
+                        }
+
+                        default:
+                            return KERR_INVALID_PARAMETER;
+                    }
+
+                    /* next */
+                    pSect++;
+                }
+                break;
+            }
+
+            case LC_SYMTAB:
+                switch (pModMachO->Hdr.filetype)
+                {
+                    case MH_OBJECT:
+                        pModMachO->offSymbols = u.pSymTab->symoff;
+                        pModMachO->cSymbols = u.pSymTab->nsyms;
+                        pModMachO->offStrings = u.pSymTab->stroff;
+                        pModMachO->cchStrings = u.pSymTab->strsize;
+                        break;
+                }
+                break;
+
+            default:
+                break;
+        } /* command switch */
+    } /* while more commands */
+
+    /*
+     * Close the last segment (if any).
+     */
+    if (pSegExtra != &pModMachO->aSegments[0])
+        pSegExtra[-1].cSections = pSectExtra - pSegExtra[-1].paSections;
+
+    /*
+     * Adjust mapping addresses calculating the image size.
+     */
+    pSeg = &pModMachO->pMod->aSegments[0];
+    switch (pModMachO->Hdr.filetype)
+    {
+        case MH_OBJECT:
+        {
+            KLDRADDR cb1;
+            KSIZE cb2;
+
+            for (i = 0; i < cSegments - 1; i++)
+            {
+                cb1 = pSeg[i + 1].LinkAddress - pSeg[i].LinkAddress;
+                cb2 = (KSIZE)cb1;
+                pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(KSIZE)0;
+            }
+            cb1 = KLDR_ALIGN_ADDR(pSeg[i].cb, pSeg[i].Alignment);
+            cb2 = (KSIZE)cb1;
+            pSeg[i].cbMapped = cb2 == cb1 ? cb2 : ~(KSIZE)0;
+
+            pModMachO->cbImage = pSeg[i].RVA + cb1;
+            break;
+        }
+    }
+
+    return 0;
+}
+
+
+/** @copydoc KLDRMODOPS::pfnDestroy */
+static int kldrModMachODestroy(PKLDRMOD pMod)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    int rc = 0;
+    KU32 i, j;
+    KLDRMODMACHO_ASSERT(!pModMachO->pvMapping);
+
+    i = pMod->cSegments;
+    while (i-- > 0)
+    {
+        j = pModMachO->aSegments[i].cSections;
+        while (j-- > 0)
+        {
+            kHlpFree(pModMachO->aSegments[i].paSections[j].paFixups);
+            pModMachO->aSegments[i].paSections[j].paFixups = NULL;
+        }
+    }
+
+    if (pMod->pRdr)
+    {
+        rc = kRdrClose(pMod->pRdr);
+        pMod->pRdr = NULL;
+    }
+    pMod->u32Magic = 0;
+    pMod->pOps = NULL;
+    kHlpFree(pModMachO->pbLoadCommands);
+    pModMachO->pbLoadCommands = NULL;
+    kHlpFree(pModMachO->pchStrings);
+    pModMachO->pchStrings = NULL;
+    kHlpFree(pModMachO->pvaSymbols);
+    pModMachO->pvaSymbols = NULL;
+    kHlpFree(pModMachO);
+    return rc;
+}
+
+
+/**
+ * Gets the right base address.
+ *
+ * @returns 0 on success.
+ * @returns A non-zero status code if the BaseAddress isn't right.
+ * @param   pModMachO       The interpreter module instance
+ * @param   pBaseAddress    The base address, IN & OUT. Optional.
+ */
+static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress)
+{
+    /*
+     * Adjust the base address.
+     */
+    if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
+        *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress;
+    else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
+        *pBaseAddress = pModMachO->LinkAddress;
+
+    return 0;
+}
+
+
+
+/** @copydoc kLdrModQuerySymbol */
+static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
+                                   const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                                   PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    int rc;
+
+    /*
+     * Resolve defaults.
+     */
+    rc  = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
+    if (rc)
+        return rc;
+
+    /*
+     * Refuse segmented requests for now.
+     */
+    if (    pfKind
+        &&  (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) != KLDRSYMKIND_REQ_FLAT)
+        return KLDR_ERR_TODO;
+
+    /*
+     * Take action according to file type.
+     */
+    if (pModMachO->Hdr.filetype == MH_OBJECT)
+    {
+        rc = kldrModMachOLoadObjSymTab(pModMachO);
+        if (!rc)
+        {
+            if (    pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
+                ||  pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
+                rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
+                                                    pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
+                                                    cchSymbol, puValue, pfKind);
+            else
+                rc = KLDR_ERR_TODO; /** @todo duplicate kldrModMachOQuerySymbol32 for parsing 64-bit symbols when everything is working. */
+                /*rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
+                                                    pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol,
+                                                    cchSymbol, puValue, pfKind);*/
+
+        }
+    }
+    else
+        rc = KLDR_ERR_TODO;
+
+    return rc;
+}
+
+
+
+/**
+ * Lookup a symbol in a 32-bit symbol table.
+ *
+ * @returns See kLdrModQuerySymbol.
+ * @param   pModMachO
+ * @param   paSyms      Pointer to the symbol table.
+ * @param   cSyms       Number of symbols in the table.
+ * @param   pchStrings  Pointer to the string table.
+ * @param   cchStrings  Size of the string table.
+ * @param   BaseAddress Adjusted base address, see kLdrModQuerySymbol.
+ * @param   iSymbol     See kLdrModQuerySymbol.
+ * @param   pchSymbol   See kLdrModQuerySymbol.
+ * @param   cchSymbol   See kLdrModQuerySymbol.
+ * @param   puValue     See kLdrModQuerySymbol.
+ * @param   pfKind      See kLdrModQuerySymbol.
+ */
+static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings,
+                                          KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
+                                          PKLDRADDR puValue, KU32 *pfKind)
+{
+    /*
+     * Find a valid symbol matching the search criteria.
+     */
+    if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL)
+    {
+        /* simplify validation. */
+        if (cchStrings <= cchSymbol)
+            return KLDR_ERR_SYMBOL_NOT_FOUND;
+        cchStrings -= cchSymbol;
+
+        /* external symbols are usually at the end, so search the other way. */
+        for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--)
+        {
+            const char *psz;
+
+            /* Skip irrellevant and non-public symbols. */
+            if (paSyms[iSymbol].n_type & MACHO_N_STAB)
+                continue;
+            if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
+                continue;
+            if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/
+                continue;
+            if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/
+                continue;
+
+            /* get name */
+            if (!paSyms[iSymbol].n_un.n_strx)
+                continue;
+            if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings)
+                continue;
+            psz = &pchStrings[paSyms[iSymbol].n_un.n_strx];
+            if (psz[cchSymbol])
+                continue;
+            if (kHlpMemComp(psz, pchSymbol, cchSymbol))
+                continue;
+
+            /* match! */
+            break;
+        }
+        if (iSymbol == KU32_MAX)
+            return KLDR_ERR_SYMBOL_NOT_FOUND;
+    }
+    else
+    {
+        if (iSymbol >= cSyms)
+            return KLDR_ERR_SYMBOL_NOT_FOUND;
+        if (paSyms[iSymbol].n_type & MACHO_N_STAB)
+            return KLDR_ERR_SYMBOL_NOT_FOUND;
+        if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
+            return KLDR_ERR_SYMBOL_NOT_FOUND;
+    }
+
+    /*
+     * Calc the return values.
+     */
+    if (pfKind)
+    {
+        if (    pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
+            ||  pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
+            *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE;
+        else
+            *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE;
+        if (paSyms[iSymbol].n_desc & N_WEAK_DEF)
+            *pfKind |= KLDRSYMKIND_WEAK;
+    }
+
+    switch (paSyms[iSymbol].n_type & MACHO_N_TYPE)
+    {
+        case MACHO_N_SECT:
+        {
+            PKLDRMODMACHOSECT pSect;
+            KLDRADDR RVA;
+            if ((KU32)(paSyms[iSymbol].n_sect - 1) >= pModMachO->cSections)
+                return KLDR_ERR_MACHO_BAD_SYMBOL;
+            pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1];
+
+            RVA = paSyms[iSymbol].n_value - pModMachO->LinkAddress;
+            if (RVA - pSect->RVA >= pSect->cb)
+                return KLDR_ERR_MACHO_BAD_SYMBOL;
+            if (puValue)
+                *puValue = RVA + BaseAddress;
+
+            if (    pfKind
+                &&  (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)))
+                *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE;
+            break;
+        }
+
+        case MACHO_N_ABS:
+            if (puValue)
+                *puValue = paSyms[iSymbol].n_value;
+            /*if (pfKind)
+                pfKind |= KLDRSYMKIND_ABS;*/
+            break;
+
+        case MACHO_N_PBUD:
+        case MACHO_N_INDR:
+            /** @todo implement indirect and prebound symbols. */
+        default:
+            KLDRMODMACHO_ASSERT(0);
+            return KLDR_ERR_TODO;
+    }
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModEnumSymbols */
+static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
+                                   KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    int rc;
+
+    /*
+     * Resolve defaults.
+     */
+    rc  = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress);
+    if (rc)
+        return rc;
+
+    /*
+     * Take action according to file type.
+     */
+    if (pModMachO->Hdr.filetype == MH_OBJECT)
+    {
+        rc = kldrModMachOLoadObjSymTab(pModMachO);
+        if (!rc)
+        {
+            if (    pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
+                ||  pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
+                rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
+                                                    pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress,
+                                                    fFlags, pfnCallback, pvUser);
+            else
+                rc = KLDR_ERR_TODO; /** @todo duplicate kldrModMachOQuerySymbol32 for parsing 64-bit symbols when everything is working. */
+                /*rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols,
+                                                    pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, pfnCallback, pvUser);*/
+        }
+    }
+    else
+        rc = KLDR_ERR_TODO;
+
+    return rc;
+}
+
+
+/**
+ * Enum a 32-bit symbol table.
+ *
+ * @returns See kLdrModQuerySymbol.
+ * @param   pModMachO
+ * @param   paSyms      Pointer to the symbol table.
+ * @param   cSyms       Number of symbols in the table.
+ * @param   pchStrings  Pointer to the string table.
+ * @param   cchStrings  Size of the string table.
+ * @param   BaseAddress Adjusted base address, see kLdrModEnumSymbols.
+ * @param   fFlags      See kLdrModEnumSymbols.
+ * @param   pfnCallback See kLdrModEnumSymbols.
+ * @param   pvUser      See kLdrModEnumSymbols.
+ */
+static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms,
+                                          const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress,
+                                          KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
+{
+    const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
+                            || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
+                             ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT;
+    KU32 iSym;
+    int rc;
+
+    /*
+     * Iterate the symbol table.
+     */
+    for (iSym = 0; iSym < cSyms; iSym++)
+    {
+        KU32 fKind;
+        KLDRADDR uValue;
+        const char *psz;
+        KSIZE cch;
+
+        /* Skip debug symbols and undefined symbols. */
+        if (paSyms[iSym].n_type & MACHO_N_STAB)
+            continue;
+        if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
+            continue;
+
+        /* Skip non-public symbols unless they are requested explicitly. */
+        if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL))
+        {
+            if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/
+                continue;
+            if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/
+                continue;
+            if (!paSyms[iSym].n_un.n_strx)
+                continue;
+        }
+
+        /*
+         * Gather symbol info
+         */
+
+        /* name */
+        if ((KU32)paSyms[iSym].n_un.n_strx >= cchStrings)
+            return KLDR_ERR_MACHO_BAD_SYMBOL;
+        psz = &pchStrings[paSyms[iSym].n_un.n_strx];
+        cch = kHlpStrLen(psz);
+        if (!cch)
+            psz = NULL;
+
+        /* kind & value */
+        fKind = fKindBase;
+        if (paSyms[iSym].n_desc & N_WEAK_DEF)
+            fKind |= KLDRSYMKIND_WEAK;
+        switch (paSyms[iSym].n_type & MACHO_N_TYPE)
+        {
+            case MACHO_N_SECT:
+            {
+                PKLDRMODMACHOSECT pSect;
+                if ((KU32)(paSyms[iSym].n_sect - 1) >= pModMachO->cSections)
+                    return KLDR_ERR_MACHO_BAD_SYMBOL;
+                pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1];
+
+                uValue = paSyms[iSym].n_value - pModMachO->LinkAddress;
+                if (uValue - pSect->RVA >= pSect->cb)
+                    return KLDR_ERR_MACHO_BAD_SYMBOL;
+                uValue += BaseAddress;
+
+                if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))
+                    fKind |= KLDRSYMKIND_CODE;
+                else
+                    fKind |= KLDRSYMKIND_NO_TYPE;
+                break;
+            }
+
+            case MACHO_N_ABS:
+                uValue = paSyms[iSym].n_value;
+                fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/;
+                break;
+
+            case MACHO_N_PBUD:
+            case MACHO_N_INDR:
+                /** @todo implement indirect and prebound symbols. */
+            default:
+                KLDRMODMACHO_ASSERT(0);
+                return KLDR_ERR_TODO;
+        }
+
+        /*
+         * Do callback.
+         */
+        rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser);
+        if (rc)
+            return rc;
+    }
+    return 0;
+}
+
+
+/** @copydoc kLdrModGetImport */
+static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    if (pModMachO->Hdr.filetype == MH_OBJECT)
+        return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
+
+    /* later */
+    return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
+}
+
+
+/** @copydoc kLdrModNumberOfImports */
+static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    if (pModMachO->Hdr.filetype == MH_OBJECT)
+        return 0;
+
+    /* later */
+    return 0;
+}
+
+
+/** @copydoc kLdrModGetStackInfo */
+static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
+{
+    /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
+
+    pStackInfo->Address = NIL_KLDRADDR;
+    pStackInfo->LinkAddress = NIL_KLDRADDR;
+    pStackInfo->cbStack = pStackInfo->cbStackThread = 0;
+    /* later */
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModQueryMainEntrypoint */
+static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
+{
+#if 0
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    int rc;
+
+    /*
+     * Resolve base address alias if any.
+     */
+    rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress);
+    if (rc)
+        return rc;
+
+    /*
+     * Convert the address from the header.
+     */
+    *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
+        ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint
+        : NIL_KLDRADDR;
+#else
+    *pMainEPAddress = NIL_KLDRADDR;
+#endif
+    return 0;
+}
+
+
+/** @copydoc kLdrModEnumDbgInfo */
+static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
+{
+#if 0
+    PKLDRMODMACHO                      pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    const IMAGE_DEBUG_DIRECTORY    *pDbgDir;
+    KU32                            iDbgInfo;
+    KU32                            cb;
+    int                             rc;
+
+    /*
+     * Check that there is a debug directory first.
+     */
+    cb = pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+    if (    cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
+        ||  !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
+        return 0;
+
+    /*
+     * Make sure we've got mapped bits.
+     */
+    rc = kldrModMachOBitsAndBaseAddress(pModMachO, &pvBits, NULL);
+    if (rc)
+        return rc;
+
+    /*
+     * Enumerate the debug directory.
+     */
+    pDbgDir = KLDRMODMACHO_RVA2TYPE(pvBits,
+                                 pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
+                                 const IMAGE_DEBUG_DIRECTORY *);
+    for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
+    {
+        KLDRDBGINFOTYPE     enmDbgInfoType;
+
+        /* convert the type. */
+        switch (pDbgDir->Type)
+        {
+            case IMAGE_DEBUG_TYPE_UNKNOWN:
+            case IMAGE_DEBUG_TYPE_FPO:
+            case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
+            case IMAGE_DEBUG_TYPE_MISC:
+            case IMAGE_DEBUG_TYPE_EXCEPTION:
+            case IMAGE_DEBUG_TYPE_FIXUP:
+            case IMAGE_DEBUG_TYPE_BORLAND:
+            default:
+                enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
+                break;
+            case IMAGE_DEBUG_TYPE_CODEVIEW:
+                enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
+                break;
+        }
+
+        rc = pfnCallback(pMod, iDbgInfo,
+                         enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
+                         pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
+                         pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
+                         pDbgDir->SizeOfData,
+                         NULL,
+                         pvUser);
+        if (rc)
+            break;
+
+        /* next */
+        if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
+            break;
+    }
+
+    return rc;
+#else
+    return 0;
+#endif
+}
+
+
+/** @copydoc kLdrModHasDbgInfo */
+static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
+{
+    /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/
+
+#if 0
+    /*
+     * Base this entirely on the presence of a debug directory.
+     */
+    if (    pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
+            < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
+        ||  !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
+        return KLDR_ERR_NO_DEBUG_INFO;
+    return 0;
+#else
+    return KLDR_ERR_NO_DEBUG_INFO;
+#endif
+}
+
+
+/** @copydoc kLdrModMap */
+static int kldrModMachOMap(PKLDRMOD pMod)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    unsigned fFixed;
+    KU32 i;
+    void *pvBase;
+    int rc;
+
+    /*
+     * Already mapped?
+     */
+    if (pModMachO->pvMapping)
+        return KLDR_ERR_ALREADY_MAPPED;
+
+    /*
+     * Map it.
+     */
+    /* fixed image? */
+    fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
+          || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
+    if (!fFixed)
+        pvBase = NULL;
+    else
+    {
+        pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
+        if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
+            return KLDR_ERR_ADDRESS_OVERFLOW;
+    }
+
+    /* try do the prepare */
+    if (pModMachO->fMapUsingLoadCommandSections)
+        return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
+    else
+    {
+        rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
+        if (rc)
+            return rc;
+    }
+
+    /*
+     * Update the segments with their map addresses.
+     */
+    for (i = 0; i < pMod->cSegments; i++)
+    {
+        if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
+            pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
+    }
+    pModMachO->pvMapping = pvBase;
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModUnmap */
+static int kldrModMachOUnmap(PKLDRMOD pMod)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    KU32 i;
+    int rc;
+
+    /*
+     * Mapped?
+     */
+    if (!pModMachO->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Try unmap the image.
+     */
+    if (pModMachO->fMapUsingLoadCommandSections)
+        return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
+    else
+    {
+        rc = kRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
+        if (rc)
+            return rc;
+    }
+
+    /*
+     * Update the segments to reflect that they aren't mapped any longer.
+     */
+    pModMachO->pvMapping = NULL;
+    for (i = 0; i < pMod->cSegments; i++)
+        pMod->aSegments[i].MapAddress = 0;
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModAllocTLS */
+static int kldrModMachOAllocTLS(PKLDRMOD pMod)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+
+    /*
+     * Mapped?
+     */
+    if (!pModMachO->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+    return 0;
+}
+
+
+/** @copydoc kLdrModFreeTLS */
+static void kldrModMachOFreeTLS(PKLDRMOD pMod)
+{
+}
+
+
+/** @copydoc kLdrModReload */
+static int kldrModMachOReload(PKLDRMOD pMod)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+
+    /*
+     * Mapped?
+     */
+    if (!pModMachO->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /* the file provider does it all */
+    return kRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments);
+}
+
+
+/** @copydoc kLdrModFixupMapping */
+static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    int rc, rc2;
+
+    /*
+     * Mapped?
+     */
+    if (!pModMachO->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Before doing anything we'll have to make all pages writable.
+     */
+    if (pModMachO->fMapUsingLoadCommandSections)
+        return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
+    else
+    {
+        rc = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
+        if (rc)
+            return rc;
+    }
+
+    /*
+     * Resolve imports and apply base relocations.
+     */
+    rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (KUPTR)pModMachO->pvMapping, pModMachO->LinkAddress,
+                                  pfnGetImport, pvUser);
+
+    /*
+     * Restore protection.
+     */
+    if (pModMachO->fMapUsingLoadCommandSections)
+        rc2 = KLDR_ERR_TODO; /* deal with this if it ever occurs. */
+    else
+        rc2 = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
+    if (!rc && rc2)
+        rc = rc2;
+    return rc;
+}
+
+
+/**
+ * MH_OBJECT: Resolves undefined symbols (imports).
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModMachO       The Mach-O module interpreter instance.
+ * @param   pfnGetImport    The callback for resolving an imported symbol.
+ * @param   pvUser          User argument to the callback.
+ */
+static int  kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    const KU32 cSyms = pModMachO->cSymbols;
+    KU32 iSym;
+    int rc;
+
+    /*
+     * Ensure that we've got the symbol table and section fixups handy.
+     */
+    rc = kldrModMachOLoadObjSymTab(pModMachO);
+    if (rc)
+        return rc;
+
+    /*
+     * Iterate the symbol table and resolve undefined symbols.
+     * We currently ignore REFERENCE_TYPE.
+     */
+    if (    pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
+        ||  pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
+    {
+        macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols;
+        for (iSym = 0; iSym < cSyms; iSym++)
+        {
+            /* skip stabs */
+            if (paSyms[iSym].n_type & MACHO_N_STAB)
+                continue;
+
+            if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
+            {
+                const char *pszSymbol;
+                KSIZE cchSymbol;
+                KU32 fKind = KLDRSYMKIND_REQ_FLAT;
+                KLDRADDR Value;
+
+                /** @todo Implement N_REF_TO_WEAK. */
+                if (paSyms[iSym].n_desc & N_REF_TO_WEAK)
+                    return KLDR_ERR_TODO;
+
+                /* Get the symbol name and try resolve it. */
+                if ((KU32)paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
+                    return KLDR_ERR_MACHO_BAD_SYMBOL;
+                pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
+                cchSymbol = kHlpStrLen(pszSymbol);
+                rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
+                                  &Value, &fKind, pvUser);
+                if (rc)
+                {
+                    /* weak reference? */
+                    if (!(paSyms[iSym].n_desc & N_WEAK_REF))
+                        break;
+                    Value = 0;
+                }
+
+                /* Update the symbol. */
+                paSyms[iSym].n_value = (KU32)Value;
+                if (paSyms[iSym].n_value != Value)
+                {
+                    rc = KLDR_ERR_ADDRESS_OVERFLOW;
+                    break;
+                }
+            }
+            else if (paSyms[iSym].n_desc & N_WEAK_DEF)
+            {
+                /** @todo implement weak symbols. */
+                /*return KLDR_ERR_TODO; - ignored for now. */
+            }
+        }
+    }
+    else
+    {
+        /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
+        macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols;
+        for (iSym = 0; iSym < cSyms; iSym++)
+        {
+            /* skip stabs */
+            if (paSyms[iSym].n_type & MACHO_N_STAB)
+                continue;
+
+            if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
+            {
+                const char *pszSymbol;
+                KSIZE cchSymbol;
+                KU32 fKind = KLDRSYMKIND_REQ_FLAT;
+                KLDRADDR Value;
+
+                /** @todo Implement N_REF_TO_WEAK. */
+                if (paSyms[iSym].n_desc & N_REF_TO_WEAK)
+                    return KLDR_ERR_TODO;
+
+                /* Get the symbol name and try resolve it. */
+                if (paSyms[iSym].n_un.n_strx >= pModMachO->cchStrings)
+                    return KLDR_ERR_MACHO_BAD_SYMBOL;
+                pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx];
+                cchSymbol = kHlpStrLen(pszSymbol);
+                rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL,
+                                  &Value, &fKind, pvUser);
+                if (rc)
+                {
+                    /* weak reference? */
+                    if (!(paSyms[iSym].n_desc & N_WEAK_REF))
+                        break;
+                    Value = 0;
+                }
+
+                /* Update the symbol. */
+                paSyms[iSym].n_value = Value;
+                if (paSyms[iSym].n_value != Value)
+                {
+                    rc = KLDR_ERR_ADDRESS_OVERFLOW;
+                    break;
+                }
+            }
+            else if (paSyms[iSym].n_desc & N_WEAK_DEF)
+            {
+                /** @todo implement weak symbols. */
+                /*return KLDR_ERR_TODO; - ignored for now. */
+            }
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModMachO       The Mach-O module interpreter instance.
+ * @param   pvMapping       The mapping to fixup.
+ * @param   NewBaseAddress  The address to fixup the mapping to.
+ * @param   OldBaseAddress  The address the mapping is currently fixed up to.
+ */
+static int  kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress)
+{
+    KU32 iSeg;
+    int rc;
+
+
+    /*
+     * Ensure that we've got the symbol table and section fixups handy.
+     */
+    rc = kldrModMachOLoadObjSymTab(pModMachO);
+    if (rc)
+        return rc;
+
+    /*
+     * Iterate over the segments and their sections and apply fixups.
+     */
+    for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++)
+    {
+        PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg];
+        KU32 iSect;
+
+        for (iSect = 0; iSect < pSeg->cSections; iSect++)
+        {
+            PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect];
+            KU8 *pbSectBits;
+
+            /* skip sections without fixups. */
+            if (!pSect->cFixups)
+                continue;
+
+            /* lazy load (and endian convert) the fixups. */
+            if (!pSect->paFixups)
+            {
+                rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
+                if (rc)
+                    break;
+            }
+
+            /*
+             * Apply the fixups.
+             */
+            pbSectBits = (KU8 *)pvMapping + (KUPTR)pSect->RVA;
+            if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
+                rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect,
+                                                          (macho_nlist_32_t *)pModMachO->pvaSymbols,
+                                                          pModMachO->cSymbols, NewBaseAddress);
+            else
+                rc = KLDR_ERR_TODO; /* save space for now. */
+            if (rc)
+                break;
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ * Applies generic fixups to a section in an image of the same endian-ness
+ * as the host CPU.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModMachO       The Mach-O module interpreter instance.
+ * @param   pbSectBits      Pointer to the section bits.
+ * @param   pFixupSect      The section being fixed up.
+ * @param   NewBaseAddress  The new base image address.
+ */
+static int  kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect,
+                                                 macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress)
+{
+    const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
+    const KU32 cFixups = pFixupSect->cFixups;
+    KSIZE cbSectBits = (KSIZE)pFixupSect->cb;
+    const KU8 *pbSectVirginBits;
+    KU32 iFixup;
+    KLDRPU uFixVirgin;
+    KLDRPU uFix;
+    KLDRADDR SymAddr;
+    int rc;
+
+    /*
+     * Find the virgin bits.
+     */
+    if (pFixupSect->offFile != -1)
+    {
+        rc = kldrModMachOMapVirginBits(pModMachO);
+        if (rc)
+            return rc;
+        pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile;
+    }
+    else
+        pbSectVirginBits = NULL;
+
+    /*
+     * Iterate the fixups and apply them.
+     */
+    for (iFixup = 0; iFixup < cFixups; iFixup++)
+    {
+        union
+        {
+            macho_relocation_info_t     r;
+            scattered_relocation_info_t s;
+        } Fixup;
+        Fixup.r = paFixups[iFixup];
+
+        if (!(Fixup.r.r_address & R_SCATTERED))
+        {
+            /* sanity */
+            if ((KU32)Fixup.r.r_address >= cbSectBits)
+                return KLDR_ERR_BAD_FIXUP;
+
+            /* calc fixup addresses. */
+            uFix.pv = pbSectBits + Fixup.r.r_address;
+            uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0;
+
+            /*
+             * Calc the symbol value.
+             */
+            /* Calc the linked symbol address / addend. */
+            switch (Fixup.r.r_length)
+            {
+                /** @todo Deal with unaligned accesses on non x86 platforms. */
+                case 0: SymAddr = *uFixVirgin.pi8; break;
+                case 1: SymAddr = *uFixVirgin.pi16; break;
+                case 2: SymAddr = *uFixVirgin.pi32; break;
+                case 3: SymAddr = *uFixVirgin.pi64; break;
+            }
+            if (Fixup.r.r_pcrel)
+                SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress;
+
+            /* Add symbol / section address. */
+            if (Fixup.r.r_extern)
+            {
+                const macho_nlist_32_t *pSym;
+                if (Fixup.r.r_symbolnum >= cSyms)
+                    return KLDR_ERR_BAD_FIXUP;
+                pSym = &paSyms[Fixup.r.r_symbolnum];
+
+                if (pSym->n_type & MACHO_N_STAB)
+                    return KLDR_ERR_BAD_FIXUP;
+
+                switch (pSym->n_type & MACHO_N_TYPE)
+                {
+                    case MACHO_N_SECT:
+                    {
+                        PKLDRMODMACHOSECT pSymSect;
+                        if ((KU32)pSym->n_sect - 1 > pModMachO->cSections)
+                            return KLDR_ERR_MACHO_BAD_SYMBOL;
+                        pSymSect = &pModMachO->paSections[pSym->n_sect - 1];
+
+                        SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
+                        break;
+                    }
+
+                    case MACHO_N_UNDF:
+                    case MACHO_N_ABS:
+                        SymAddr += pSym->n_value;
+                        break;
+
+                    case MACHO_N_INDR:
+                    case MACHO_N_PBUD:
+                        return KLDR_ERR_TODO;
+                    default:
+                        return KLDR_ERR_MACHO_BAD_SYMBOL;
+                }
+            }
+            else if (Fixup.r.r_symbolnum != R_ABS)
+            {
+                PKLDRMODMACHOSECT pSymSect;
+                if (Fixup.r.r_symbolnum > pModMachO->cSections)
+                    return KLDR_ERR_BAD_FIXUP;
+                pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1];
+
+                SymAddr -= pSymSect->LinkAddress;
+                SymAddr += pSymSect->RVA + NewBaseAddress;
+            }
+
+            /* adjust for PC relative */
+            if (Fixup.r.r_pcrel)
+                SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
+        }
+        else
+        {
+            PKLDRMODMACHOSECT pSymSect;
+            KU32 iSymSect;
+            KLDRADDR Value;
+
+            /* sanity */
+            KLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
+            if ((KU32)Fixup.s.r_address >= cbSectBits)
+                return KLDR_ERR_BAD_FIXUP;
+
+            /* calc fixup addresses. */
+            uFix.pv = pbSectBits + Fixup.s.r_address;
+            uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.s.r_address : 0;
+
+            /*
+             * Calc the symbol value.
+             */
+            /* The addend is stored in the code. */
+            switch (Fixup.s.r_length)
+            {
+                case 0: SymAddr = *uFixVirgin.pi8; break;
+                case 1: SymAddr = *uFixVirgin.pi16; break;
+                case 2: SymAddr = *uFixVirgin.pi32; break;
+                case 3: SymAddr = *uFixVirgin.pi64; break;
+            }
+            if (Fixup.s.r_pcrel)
+                SymAddr += Fixup.s.r_address;
+            Value = Fixup.s.r_value;
+            SymAddr -= Value;                   /* (-> addend only) */
+
+            /* Find the section number from the r_value. */
+            pSymSect = NULL;
+            for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++)
+            {
+                KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress;
+                if (off < pModMachO->paSections[iSymSect].cb)
+                {
+                    pSymSect = &pModMachO->paSections[iSymSect];
+                    break;
+                }
+                else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */
+                    pSymSect = &pModMachO->paSections[iSymSect];
+            }
+            if (!pSymSect)
+                return KLDR_ERR_BAD_FIXUP;
+
+            /* Calc the symbol address. */
+            SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
+            if (Fixup.s.r_pcrel)
+                SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
+
+            Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
+            Fixup.r.r_type   = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type;
+        }
+
+        /*
+         * Write back the fixed up value.
+         */
+        if (Fixup.r.r_type == GENERIC_RELOC_VANILLA)
+        {
+            switch (Fixup.r.r_length)
+            {
+                case 0: *uFix.pu8  = (KU8)SymAddr; break;
+                case 1: *uFix.pu16 = (KU16)SymAddr; break;
+                case 2: *uFix.pu32 = (KU32)SymAddr; break;
+                case 3: *uFix.pu64 = (KU64)SymAddr; break;
+            }
+        }
+        else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF)
+            return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE;
+        else
+            return KLDR_ERR_BAD_FIXUP;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Loads the symbol table for a MH_OBJECT file.
+ *
+ * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModMachO       The Mach-O module interpreter instance.
+ */
+static int  kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO)
+{
+    int rc = 0;
+
+    if (    !pModMachO->pvaSymbols
+        &&  pModMachO->cSymbols)
+    {
+        KSIZE cbSyms;
+        KSIZE cbSym;
+        void *pvSyms;
+        void *pvStrings;
+
+        /* sanity */
+        if (    !pModMachO->offSymbols
+            ||  (pModMachO->cchStrings && !pModMachO->offStrings))
+            return KLDR_ERR_MACHO_BAD_OBJECT_FILE;
+
+        /* allocate */
+        cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE
+             || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
+             ? sizeof(macho_nlist_32_t)
+             : sizeof(macho_nlist_64_t);
+        cbSyms = pModMachO->cSymbols * cbSym;
+        if (cbSyms / cbSym != pModMachO->cSymbols)
+            return KLDR_ERR_SIZE_OVERFLOW;
+        rc = KERR_NO_MEMORY;
+        pvSyms = kHlpAlloc(cbSyms);
+        if (pvSyms)
+        {
+            if (pModMachO->cchStrings)
+                pvStrings = kHlpAlloc(pModMachO->cchStrings);
+            else
+                pvStrings = kHlpAllocZ(4);
+            if (pvStrings)
+            {
+                /* read */
+                rc = kRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols);
+                if (!rc && pModMachO->cchStrings)
+                    rc = kRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings);
+                if (!rc)
+                {
+                    pModMachO->pvaSymbols = pvSyms;
+                    pModMachO->pchStrings = (char *)pvStrings;
+
+                    /* perform endian conversion? */
+                    if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
+                    {
+                        KU32 cLeft = pModMachO->cSymbols;
+                        macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms;
+                        while (cLeft-- > 0)
+                        {
+                            pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
+                            pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
+                            pSym->n_value = K_E2E_U32(pSym->n_value);
+                            pSym++;
+                        }
+                    }
+                    else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
+                    {
+                        KU32 cLeft = pModMachO->cSymbols;
+                        macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms;
+                        while (cLeft-- > 0)
+                        {
+                            pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx);
+                            pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc);
+                            pSym->n_value = K_E2E_U64(pSym->n_value);
+                            pSym++;
+                        }
+                    }
+
+                    return 0;
+                }
+                kHlpFree(pvStrings);
+            }
+            kHlpFree(pvSyms);
+        }
+    }
+    else
+        KLDRMODMACHO_ASSERT(pModMachO->pchStrings);
+
+    return rc;
+}
+
+
+/**
+ * Loads the fixups at the given address and performs endian
+ * conversion if necessary.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModMachO       The Mach-O module interpreter instance.
+ * @param   offFixups       The file offset of the fixups.
+ * @param   cFixups         The number of fixups to load.
+ * @param   ppaFixups       Where to put the pointer to the allocated fixup array.
+ */
+static int  kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups)
+{
+    macho_relocation_info_t *paFixups;
+    KSIZE cbFixups;
+    int rc;
+
+    /* allocate the memory. */
+    cbFixups = cFixups * sizeof(*paFixups);
+    if (cbFixups / sizeof(*paFixups) != cFixups)
+        return KLDR_ERR_SIZE_OVERFLOW;
+    paFixups = (macho_relocation_info_t *)kHlpAlloc(cbFixups);
+    if (!paFixups)
+        return KERR_NO_MEMORY;
+
+    /* read the fixups. */
+    rc = kRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups);
+    if (!rc)
+    {
+        *ppaFixups = paFixups;
+
+        /* do endian conversion if necessary. */
+        if (    pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
+            ||  pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
+        {
+            KU32 iFixup;
+            for (iFixup = 0; iFixup < cFixups; iFixup++)
+            {
+                KU32 *pu32 = (KU32 *)&paFixups[iFixup];
+                pu32[0] = K_E2E_U32(pu32[0]);
+                pu32[1] = K_E2E_U32(pu32[1]);
+            }
+        }
+    }
+    else
+        kHlpFree(paFixups);
+    return rc;
+}
+
+
+/**
+ * Maps the virgin file bits into memory if not already done.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModMachO       The Mach-O module interpreter instance.
+ */
+static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO)
+{
+    int rc = 0;
+    if (!pModMachO->pvBits)
+        rc = kRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits);
+    return rc;
+}
+
+
+/** @copydoc kLdrModCallInit */
+static int kldrModMachOCallInit(PKLDRMOD pMod, KUPTR uHandle)
+{
+    /* later */
+    return 0;
+}
+
+
+/** @copydoc kLdrModCallTerm */
+static int kldrModMachOCallTerm(PKLDRMOD pMod, KUPTR uHandle)
+{
+    /* later */
+    return 0;
+}
+
+
+/** @copydoc kLdrModCallThread */
+static int kldrModMachOCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
+{
+    /* Relevant for Mach-O? */
+    return 0;
+}
+
+
+/** @copydoc kLdrModSize */
+static KLDRADDR kldrModMachOSize(PKLDRMOD pMod)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    return pModMachO->cbImage;
+}
+
+
+/** @copydoc kLdrModGetBits */
+static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODMACHO  pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    KU32        i;
+    int         rc;
+
+    /*
+     * Zero the entire buffer first to simplify things.
+     */
+    kHlpMemSet(pvBits, 0, (KSIZE)pModMachO->cbImage);
+
+    /*
+     * When possible use the segment table to load the data.
+     * If not iterate the load commands and execute the segment / section loads.
+     */
+    if (pModMachO->fMapUsingLoadCommandSections)
+        return KLDR_ERR_TODO; /* deal with this if it ever occurs. */
+    else
+    {
+        for (i = 0; i < pMod->cSegments; i++)
+        {
+            /* skip it? */
+            if (    pMod->aSegments[i].cbFile == -1
+                ||  pMod->aSegments[i].offFile == -1
+                ||  pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
+                ||  !pMod->aSegments[i].Alignment)
+                continue;
+            rc = kRdrRead(pMod->pRdr,
+                             (KU8 *)pvBits + (pMod->aSegments[i].LinkAddress - pModMachO->LinkAddress),
+                             pMod->aSegments[i].cbFile,
+                             pMod->aSegments[i].offFile);
+            if (rc)
+                return rc;
+        }
+    }
+
+    /*
+     * Perform relocations.
+     */
+    return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser);
+}
+
+
+/** @copydoc kLdrModRelocateBits */
+static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                                    PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;
+    int rc;
+
+    /*
+     * Call workers to do the jobs.
+     */
+    if (pModMachO->Hdr.filetype == MH_OBJECT)
+    {
+        rc = kldrModMachOObjDoImports(pModMachO, pfnGetImport, pvUser);
+        if (!rc)
+            rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress);
+
+    }
+    else
+        rc = KLDR_ERR_TODO;
+    /*{
+        rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
+        if (!rc)
+            rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser);
+    }*/
+
+    return rc;
+}
+
+
+/**
+ * The Mach-O module interpreter method table.
+ */
+KLDRMODOPS g_kLdrModMachOOps =
+{
+    "Mach-O",
+    NULL,
+    kldrModMachOCreate,
+    kldrModMachODestroy,
+    kldrModMachOQuerySymbol,
+    kldrModMachOEnumSymbols,
+    kldrModMachOGetImport,
+    kldrModMachONumberOfImports,
+    NULL /* can execute one is optional */,
+    kldrModMachOGetStackInfo,
+    kldrModMachOQueryMainEntrypoint,
+    NULL,
+    NULL,
+    kldrModMachOEnumDbgInfo,
+    kldrModMachOHasDbgInfo,
+    kldrModMachOMap,
+    kldrModMachOUnmap,
+    kldrModMachOAllocTLS,
+    kldrModMachOFreeTLS,
+    kldrModMachOReload,
+    kldrModMachOFixupMapping,
+    kldrModMachOCallInit,
+    kldrModMachOCallTerm,
+    kldrModMachOCallThread,
+    kldrModMachOSize,
+    kldrModMachOGetBits,
+    kldrModMachORelocateBits,
+    NULL, /** @todo mostly done */
+    42 /* the end */
+};
+
Index: /trunk/kLdr/kLdrModNative.c
===================================================================
--- /trunk/kLdr/kLdrModNative.c	(revision 2)
+++ /trunk/kLdr/kLdrModNative.c	(revision 2)
@@ -0,0 +1,1159 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Module Interpreter for the Native Loaders.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# include <os2.h>
+
+# ifndef LIBPATHSTRICT
+#  define LIBPATHSTRICT 3
+# endif
+  extern APIRET DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction);
+# define QHINF_EXEINFO       1 /* NE exeinfo. */
+# define QHINF_READRSRCTBL   2 /* Reads from the resource table. */
+# define QHINF_READFILE      3 /* Reads from the executable file. */
+# define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */
+# define QHINF_LIBPATH       5 /* Gets the entire libpath. */
+# define QHINF_FIXENTRY      6 /* NE only */
+# define QHINF_STE           7 /* NE only */
+# define QHINF_MAPSEL        8 /* NE only */
+
+#elif K_OS == K_OS_WINDOWS
+# undef IMAGE_NT_SIGNATURE
+# undef IMAGE_DOS_SIGNATURE
+# include <windows.h>
+# ifndef IMAGE_SCN_TYPE_NOLOAD
+#  define IMAGE_SCN_TYPE_NOLOAD 0x00000002
+# endif
+
+/*#elif defined(__NT__)
+#include <winnt.h> */
+
+#elif K_OS == K_OS_DARWIN
+# include <dlfcn.h>
+# include <errno.h>
+
+#else
+# error "port me"
+#endif
+
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRMODNATIVE_STRICT
+ * Define KLDRMODNATIVE_STRICT to enabled strict checks in KLDRMODNATIVE. */
+#define KLDRMODNATIVE_STRICT 1
+
+/** @def KLDRMODNATIVE_ASSERT
+ * Assert that an expression is true when KLDR_STRICT is defined.
+ */
+#ifdef KLDRMODNATIVE_STRICT
+# define KLDRMODNATIVE_ASSERT(expr)  kHlpAssert(expr)
+#else
+# define KLDRMODNATIVE_ASSERT(expr)  do {} while (0)
+#endif
+
+#if K_OS == K_OS_WINDOWS
+/** @def KLDRMODNATIVE_RVA2TYPE
+ * Converts a RVA to a pointer of the specified type.
+ * @param   pvBits      The bits (image base).
+ * @param   uRVA        The image relative virtual address.
+ * @param   type        The type to cast to.
+ */
+# define KLDRMODNATIVE_RVA2TYPE(pvBits, uRVA, type) \
+        ( (type) ((KUPTR)(pvBits) + (uRVA)) )
+
+#endif /* PE OSes */
+
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Instance data for the module interpreter for the Native Loaders.
+ */
+typedef struct KLDRMODNATIVE
+{
+    /** Pointer to the module. (Follows the section table.) */
+    PKLDRMOD                    pMod;
+    /** Reserved flags. */
+    KU32                        f32Reserved;
+    /** The number of imported modules.
+     * If ~(KU32)0 this hasn't been determined yet. */
+    KU32                        cImportModules;
+#if K_OS == K_OS_OS2
+    /** The module handle. */
+    HMODULE                     hmod;
+
+#elif K_OS == K_OS_WINDOWS
+    /** The module handle. */
+    HANDLE                      hmod;
+    /** Pointer to the NT headers. */
+    const IMAGE_NT_HEADERS     *pNtHdrs;
+    /** Pointer to the section header array. */
+    const IMAGE_SECTION_HEADER *paShdrs;
+
+#elif K_OS == K_OS_DARWIN
+    /** The dlopen() handle.*/
+    void                       *pvMod;
+
+#else
+# error "Port me"
+#endif
+} KLDRMODNATIVE, *PKLDRMODNATIVE;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits);
+
+
+
+/**
+ * Use native loader to load the file opened by pRdr.
+ *
+ * @returns 0 on success and *ppMod pointing to a module instance.
+ *          On failure, a non-zero OS specific error code is returned.
+ * @param   pOps            Pointer to the registered method table.
+ * @param   pRdr            The file provider instance to use.
+ * @param   offNewHdr       The offset of the new header in MZ files. -1 if not found.
+ * @param   ppMod           Where to store the module instance pointer.
+ */
+static int kldrModNativeCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
+{
+    int rc = kLdrModOpenNative(kRdrName(pRdr), ppMod);
+    if (rc)
+        return rc;
+    rc = kRdrClose(pRdr);
+    KLDRMODNATIVE_ASSERT(!rc);
+    return 0;
+}
+
+
+/**
+ * Loads a module using the native module loader.
+ *
+ * @returns 0 on success.
+ * @returns non-zero native or kLdr status code on failure.
+ * @param   pszFilename         The filename or module name to be loaded.
+ * @param   ppMod               Where to store the module interpreter instance pointer.
+ */
+int kLdrModOpenNative(const char *pszFilename, PPKLDRMOD ppMod)
+{
+    int rc;
+
+    /*
+     * Load the image.
+     */
+#if K_OS == K_OS_OS2
+    HMODULE hmod;
+
+    rc = DosLoadModule(NULL, 0, (PCSZ)pszFilename, &hmod);
+    if (rc)
+        return rc;
+    rc = kLdrModOpenNativeByHandle((KUPTR)hmod, ppMod);
+    if (rc)
+        DosFreeModule(hmod);
+
+#elif K_OS == K_OS_WINDOWS
+    HMODULE hmod;
+
+    hmod = LoadLibrary(pszFilename);
+    if (!hmod)
+        return GetLastError();
+    rc = kLdrModOpenNativeByHandle((KUPTR)hmod, ppMod);
+    if (rc)
+        FreeLibrary(hmod);
+
+#elif K_OS == K_OS_DARWIN
+    void *pvMod;
+
+    pvMod = dlopen(pszFilename, 0);
+    if (!pvMod)
+        return ENOENT;
+    rc = kLdrModOpenNativeByHandle((KUPTR)pvMod, ppMod);
+    if (rc)
+        dlclose(pvMod);
+
+#else
+# error "Port me"
+#endif
+    return rc;
+}
+
+
+/**
+ * Creates a native module interpret for an already module already
+ * loaded by the native loader.
+ *
+ * @returns 0 on success.
+ * @returns non-zero native or kLdr status code on failure.
+ * @param   pszFilename         The filename or module name to be loaded.
+ * @param   ppMod               Where to store the module interpreter instance pointer.
+ * @remark  This will not make the native loader increment the load count.
+ */
+int kLdrModOpenNativeByHandle(KUPTR uHandle, PPKLDRMOD ppMod)
+{
+    KSIZE cb;
+    KSIZE cchFilename;
+    KU32 cSegments;
+    PKLDRMOD pMod;
+    PKLDRMODNATIVE pModNative;
+
+    /*
+     * Delcare variables, parse the module header or whatever and determin the
+     * size of the module instance.
+     */
+#if K_OS == K_OS_OS2
+    char szFilename[CCHMAXPATH];
+    int rc;
+
+    /* get the filename. */
+    rc = DosQueryModuleName((HMODULE)uHandle, sizeof(szFilename), szFilename);
+    if (rc)
+    {
+        KLDRMODNATIVE_ASSERT(rc);
+        szFilename[0] = '\0';
+    }
+
+    /* get the segment count. */
+    /** @todo DosQueryHeaderInfo should be able to get us what we want on OS/2. */
+    cSegments = 1;
+
+#elif K_OS == K_OS_WINDOWS
+    DWORD                       dw;
+    char                        szFilename[MAX_PATH];
+    const IMAGE_NT_HEADERS     *pNtHdrs;
+    const IMAGE_SECTION_HEADER *paShdrs;
+    const IMAGE_DOS_HEADER     *pDosHdr = (const IMAGE_DOS_HEADER *)uHandle;
+    unsigned                    i;
+
+    /* get the filename. */
+    dw = GetModuleFileName((HANDLE)uHandle, szFilename, sizeof(szFilename));
+    if (dw <= 0)
+    {
+        KLDRMODNATIVE_ASSERT(dw <= 0);
+        szFilename[0] = '\0';
+    }
+
+    /* get the segment count. */
+    if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
+        pNtHdrs = (const IMAGE_NT_HEADERS *)((KUPTR)pDosHdr + pDosHdr->e_lfanew);
+    else
+        pNtHdrs = (const IMAGE_NT_HEADERS *)pDosHdr;
+    if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
+    {
+        KLDRMODNATIVE_ASSERT(!"bad signature");
+        return KLDR_ERR_UNKNOWN_FORMAT;
+    }
+    if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
+    {
+        KLDRMODNATIVE_ASSERT(!"bad optional header size");
+        return KLDR_ERR_UNKNOWN_FORMAT;
+    }
+    cSegments = pNtHdrs->FileHeader.NumberOfSections + 1;
+    paShdrs = (const IMAGE_SECTION_HEADER *)(pNtHdrs + 1);
+
+#elif K_OS == K_OS_DARWIN
+    char    szFilename[1] = "";
+    cSegments = 0; /** @todo Figure out the Mac OS X dynamic loader. */
+
+#else
+# error "Port me"
+#endif
+
+    /*
+     * Calc the instance size, allocate and initialize it.
+     */
+    cchFilename = kHlpStrLen(szFilename);
+    cb = K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16)
+       + K_OFFSETOF(KLDRMOD, aSegments[cSegments])
+       + cchFilename + 1;
+    pModNative = (PKLDRMODNATIVE)kHlpAlloc(cb);
+    if (!pModNative)
+        return KERR_NO_MEMORY;
+
+    /* KLDRMOD */
+    pMod = (PKLDRMOD)((KU8 *)pModNative + K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16));
+    pMod->pvData = pModNative;
+    pMod->pRdr = NULL;
+    pMod->pOps = NULL;      /* set upon success. */
+    pMod->cSegments = cSegments;
+    pMod->cchFilename = cchFilename;
+    pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
+    kHlpMemCopy((char *)pMod->pszFilename, szFilename, cchFilename + 1);
+    pMod->pszName = kHlpGetFilename(pMod->pszFilename); /** @todo get soname */
+    pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
+#if defined(__i386__) || defined(__X86__) || defined(_M_IX86)
+    pMod->enmCpu = KCPU_I386;
+    pMod->enmArch = KCPUARCH_X86_32;
+    pMod->enmEndian = KLDRENDIAN_LITTLE;
+#elif defined(__X86_64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_IX64)
+    pMod->enmCpu = KCPU_K8;
+    pMod->enmArch = KCPUARCH_AMD64;
+    pMod->enmEndian = KLDRENDIAN_LITTLE;
+#else
+# error "Port me"
+#endif
+    pMod->enmFmt = KLDRFMT_NATIVE;
+    pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
+    pMod->u32Magic = 0;     /* set upon success. */
+
+    /* KLDRMODNATIVE */
+    pModNative->pMod = pMod;
+    pModNative->f32Reserved = 0;
+    pModNative->cImportModules = ~(KU32)0;
+
+    /*
+     * Set native instance data.
+     */
+#if K_OS == K_OS_OS2
+    pModNative->hmod = (HMODULE)uHandle;
+
+    /* just fake a segment for now. */
+    pMod->aSegments[0].pvUser = NULL;
+    pMod->aSegments[0].pchName = "fake";
+    pMod->aSegments[0].cchName = sizeof("fake") - 1;
+    pMod->aSegments[0].enmProt = KPROT_NOACCESS;
+    pMod->aSegments[0].cb = 0;
+    pMod->aSegments[0].Alignment = 0;
+    pMod->aSegments[0].LinkAddress = NIL_KLDRADDR;
+    pMod->aSegments[0].offFile = -1;
+    pMod->aSegments[0].cbFile = 0;
+    pMod->aSegments[0].RVA = NIL_KLDRADDR;
+    pMod->aSegments[0].cbMapped = 0;
+    pMod->aSegments[0].MapAddress = 0;
+
+#elif K_OS == K_OS_WINDOWS
+    pModNative->hmod = (HMODULE)uHandle;
+    pModNative->pNtHdrs = pNtHdrs;
+    pModNative->paShdrs = paShdrs;
+
+    if (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)
+        pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+            ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
+            : KLDRTYPE_SHARED_LIBRARY_FIXED;
+    else
+        pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+            ? KLDRTYPE_EXECUTABLE_RELOCATABLE
+            : KLDRTYPE_EXECUTABLE_FIXED;
+
+    /* The implied headers section. */
+    pMod->aSegments[0].pvUser = NULL;
+    pMod->aSegments[0].pchName = "TheHeaders";
+    pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1;
+    pMod->aSegments[0].enmProt = KPROT_READONLY;
+    pMod->aSegments[0].cb = pNtHdrs->OptionalHeader.SizeOfHeaders;
+    pMod->aSegments[0].Alignment = pNtHdrs->OptionalHeader.SectionAlignment;
+    pMod->aSegments[0].LinkAddress = pNtHdrs->OptionalHeader.ImageBase;
+    pMod->aSegments[0].offFile = 0;
+    pMod->aSegments[0].cbFile = pNtHdrs->OptionalHeader.SizeOfHeaders;
+    pMod->aSegments[0].RVA = 0;
+    if (pMod->cSegments > 1)
+        pMod->aSegments[0].cbMapped = paShdrs[0].VirtualAddress;
+    else
+        pMod->aSegments[0].cbMapped = pNtHdrs->OptionalHeader.SizeOfHeaders;
+    pMod->aSegments[0].MapAddress = 0;
+
+    /* The section headers. */
+    for (i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
+    {
+        const char *pch;
+
+        /* unused */
+        pMod->aSegments[i + 1].pvUser = NULL;
+        pMod->aSegments[i + 1].MapAddress = 0;
+
+        /* name */
+        pMod->aSegments[i + 1].pchName = pch = &paShdrs[i].Name[0];
+        cb = IMAGE_SIZEOF_SHORT_NAME;
+        while (     cb > 0
+               &&   (pch[cb - 1] == ' ' || pch[cb - 1] == '\0'))
+            cb--;
+        pMod->aSegments[i + 1].cchName = cb;
+
+        /* size and addresses */
+        if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+        {
+            pMod->aSegments[i + 1].cb          = paShdrs[i].Misc.VirtualSize;
+            pMod->aSegments[i + 1].LinkAddress = paShdrs[i].VirtualAddress
+                                               + pNtHdrs->OptionalHeader.ImageBase;
+            pMod->aSegments[i + 1].RVA         = paShdrs[i].VirtualAddress;
+            pMod->aSegments[i + 1].cbMapped    = paShdrs[i].Misc.VirtualSize;
+            if (i + 2 < pMod->cSegments)
+                pMod->aSegments[i + 1].cbMapped= paShdrs[i + 1].VirtualAddress
+                                               - paShdrs[i].VirtualAddress;
+        }
+        else
+        {
+            pMod->aSegments[i + 1].cb          = 0;
+            pMod->aSegments[i + 1].cbMapped    = 0;
+            pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR;
+            pMod->aSegments[i + 1].RVA         = 0;
+        }
+
+        /* file location */
+        pMod->aSegments[i + 1].offFile = paShdrs[i].PointerToRawData;
+        pMod->aSegments[i + 1].cbFile = paShdrs[i].SizeOfRawData;
+        if (    pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */
+            &&  (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped)
+            pMod->aSegments[i + 1].cbFile = pMod->aSegments[i + 1].cbMapped;
+
+        /* protection */
+        switch (  paShdrs[i].Characteristics
+                & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
+        {
+            case 0:
+            case IMAGE_SCN_MEM_SHARED:
+                pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS;
+                break;
+            case IMAGE_SCN_MEM_READ:
+            case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
+                pMod->aSegments[i + 1].enmProt = KPROT_READONLY;
+                break;
+            case IMAGE_SCN_MEM_WRITE:
+            case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
+                pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY;
+                break;
+            case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
+            case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
+                pMod->aSegments[i + 1].enmProt = KPROT_READWRITE;
+                break;
+            case IMAGE_SCN_MEM_EXECUTE:
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED:
+                pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE;
+                break;
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ:
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
+                pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ;
+                break;
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE:
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
+                pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY;
+                break;
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
+                pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE;
+                break;
+        }
+
+        /* alignment. */
+        switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
+        {
+            case 0: /* hope this is right... */
+                pMod->aSegments[i + 1].Alignment = pNtHdrs->OptionalHeader.SectionAlignment;
+                break;
+            case IMAGE_SCN_ALIGN_1BYTES:        pMod->aSegments[i + 1].Alignment = 1; break;
+            case IMAGE_SCN_ALIGN_2BYTES:        pMod->aSegments[i + 1].Alignment = 2; break;
+            case IMAGE_SCN_ALIGN_4BYTES:        pMod->aSegments[i + 1].Alignment = 4; break;
+            case IMAGE_SCN_ALIGN_8BYTES:        pMod->aSegments[i + 1].Alignment = 8; break;
+            case IMAGE_SCN_ALIGN_16BYTES:       pMod->aSegments[i + 1].Alignment = 16; break;
+            case IMAGE_SCN_ALIGN_32BYTES:       pMod->aSegments[i + 1].Alignment = 32; break;
+            case IMAGE_SCN_ALIGN_64BYTES:       pMod->aSegments[i + 1].Alignment = 64; break;
+            case IMAGE_SCN_ALIGN_128BYTES:      pMod->aSegments[i + 1].Alignment = 128; break;
+            case IMAGE_SCN_ALIGN_256BYTES:      pMod->aSegments[i + 1].Alignment = 256; break;
+            case IMAGE_SCN_ALIGN_512BYTES:      pMod->aSegments[i + 1].Alignment = 512; break;
+            case IMAGE_SCN_ALIGN_1024BYTES:     pMod->aSegments[i + 1].Alignment = 1024; break;
+            case IMAGE_SCN_ALIGN_2048BYTES:     pMod->aSegments[i + 1].Alignment = 2048; break;
+            case IMAGE_SCN_ALIGN_4096BYTES:     pMod->aSegments[i + 1].Alignment = 4096; break;
+            case IMAGE_SCN_ALIGN_8192BYTES:     pMod->aSegments[i + 1].Alignment = 8192; break;
+            default: kHlpAssert(0);          pMod->aSegments[i + 1].Alignment = 0; break;
+        }
+    }
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo Figure out the Mac OS X dynamic loader. */
+
+#else
+# error "Port me"
+#endif
+
+    /*
+     * We're done.
+     */
+    *ppMod = pMod;
+    return 0;
+}
+
+
+/** @copydoc KLDRMODOPS::pfnDestroy */
+static int kldrModNativeDestroy(PKLDRMOD pMod)
+{
+    PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+    int rc;
+
+#if K_OS == K_OS_OS2
+    rc = DosFreeModule(pModNative->hmod);
+
+#elif K_OS == K_OS_WINDOWS
+    if (FreeLibrary(pModNative->hmod))
+        rc = 0;
+    else
+        rc = GetLastError();
+
+#elif K_OS == K_OS_DARWIN
+    dlclose(pModNative->pvMod);
+
+#else
+# error "Port me"
+#endif
+
+    pMod->u32Magic = 0;
+    pMod->pOps = NULL;
+    kHlpFree(pModNative);
+    return rc;
+}
+
+
+/** @copydoc kLdrModQuerySymbol */
+static int kldrModNativeQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
+                                    const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                                    PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
+{
+    PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+    const char *pszSymbol = pchSymbol;
+#if K_OS == K_OS_OS2
+    APIRET rc;
+    PFN pfn;
+#elif K_OS == K_OS_WINDOWS
+    FARPROC pfn;
+#elif K_OS == K_OS_DARWIN
+    void *pfn;
+#else
+# error "Port me"
+#endif
+
+    /* make stack copy of the symbol if it isn't zero terminated. */
+    if (pszSymbol && pszSymbol[cchSymbol])
+    {
+        char *pszCopy = kHlpAllocA(cchSymbol + 1);
+        kHlpMemCopy(pszCopy, pchSymbol, cchSymbol);
+        pszCopy[cchSymbol] = '\0';
+        pszSymbol = pszCopy;
+    }
+
+#if K_OS == K_OS_OS2
+    if (!pchSymbol && iSymbol >= 0x10000)
+        return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+    if (puValue)
+    {
+        rc = DosQueryProcAddr(pModNative->hmod,
+                              pszSymbol ? 0 : iSymbol,
+                              (PCSZ)pszSymbol,
+                              &pfn);
+        if (rc)
+            return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc;
+        *puValue = (KUPTR)pfn;
+    }
+    if (pfKind)
+    {
+        ULONG ulProcType;
+        rc = DosQueryProcType(pModNative->hmod,
+                              pszSymbol ? 0 : iSymbol,
+                              (PCSZ)pszSymbol,
+                              &ulProcType);
+        if (rc)
+        {
+            if (puValue)
+                *puValue = 0;
+            return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc;
+        }
+        *pfKind = (ulProcType & PT_32BIT ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT)
+                | KLDRSYMKIND_NO_TYPE;
+    }
+
+#elif K_OS == K_OS_WINDOWS
+    if (!pszSymbol && iSymbol >= 0x10000)
+        return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+    pfn = GetProcAddress(pModNative->hmod, pszSymbol ? pszSymbol : (const char *)(KUPTR)iSymbol);
+    if (puValue)
+        *puValue = (KUPTR)pfn;
+    if (pfKind)
+        *pfKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
+                   ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT)
+                | KLDRSYMKIND_NO_TYPE;
+
+#elif K_OS == K_OS_DARWIN
+    if (!pszSymbol && iSymbol != NIL_KLDRMOD_SYM_ORDINAL)
+        return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+    pfn = dlsym(pModNative->pvMod, pszSymbol);
+    if (!pfn)
+        return KLDR_ERR_SYMBOL_NOT_FOUND;
+    if (puValue)
+        *puValue = (KUPTR)pfn;
+    if (pfKind)
+        *pfKind = (sizeof(KUPTR) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
+                | KLDRSYMKIND_NO_TYPE;
+
+#else
+# error "Port me"
+#endif
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModEnumSymbols */
+static int kldrModNativeEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
+                                    KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
+{
+    PKLDRMODNATIVE                  pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+    /** @todo implement export enumeration on OS/2. */
+    (void)pModNative;
+    return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    const KU32                     *paFunctions;
+    const IMAGE_EXPORT_DIRECTORY   *pExpDir;
+    const KU32                     *paRVANames;
+    const KU16                     *paOrdinals;
+    KU32                            iFunction;
+    KU32                            cFunctions;
+    KU32                            cNames;
+    int                             rc;
+
+    /*
+     * Make sure we've got mapped bits and resolve any base address aliases.
+     */
+    if (    pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
+        <   sizeof(IMAGE_EXPORT_DIRECTORY))
+        return 0; /* no exports to enumerate, return success. */
+
+    pExpDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
+                                     pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
+                                     PIMAGE_EXPORT_DIRECTORY);
+
+    /*
+     * Enumerate the ordinal exports.
+     */
+    paRVANames = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNames, const KU32 *);
+    paOrdinals = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNameOrdinals, const KU16 *);
+    paFunctions = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfFunctions, const KU32 *);
+    cFunctions = pExpDir->NumberOfFunctions;
+    cNames = pExpDir->NumberOfNames;
+    for (iFunction = 0; iFunction < cFunctions; iFunction++)
+    {
+        unsigned        fFoundName;
+        KU32            iName;
+        const KU32      uRVA = paFunctions[iFunction];
+        const KLDRADDR  uValue = BaseAddress + uRVA;
+        KU32            fKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
+                              ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
+                              | KLDRSYMKIND_NO_TYPE;
+        if (    uRVA - pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
+            <   pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
+            fKind |= KLDRSYMKIND_FORWARDER;
+
+        /*
+         * Any symbol names?
+         */
+        fFoundName = 0;
+        for (iName = 0; iName < cNames; iName++)
+        {
+            const char *pszName;
+            if (paOrdinals[iName] != iFunction)
+                continue;
+            fFoundName = 1;
+
+            pszName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, paRVANames[iName], const char *);
+            rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, strlen(pszName), NULL,
+                             uValue, fKind, pvUser);
+            if (rc)
+                return rc;
+        }
+
+        /*
+         * If no names, call once with the ordinal only.
+         */
+        if (!fFoundName)
+        {
+            rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser);
+            if (rc)
+                return rc;
+        }
+    }
+    return 0;
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo implement enumeration on darwin. */
+    (void)pModNative;
+    return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+
+}
+
+
+/** @copydoc kLdrModGetImport */
+static int kldrModNativeGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
+{
+    PKLDRMODNATIVE                  pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+    /** @todo implement import enumeration on OS/2. */
+    (void)pModNative;
+    return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    const IMAGE_IMPORT_DESCRIPTOR  *pImpDesc;
+    const char                     *pszImportName;
+    KSIZE                           cchImportName;
+    int                             rc;
+
+    /*
+     * Simple bounds check.
+     */
+    if (iImport >= (KU32)kldrModNativeNumberOfImports(pMod, pvBits))
+        return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
+
+    /*
+     * Get the name.
+     */
+    pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
+                                      pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
+                                      + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport,
+                                      const IMAGE_IMPORT_DESCRIPTOR *);
+    pszImportName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pImpDesc->Name, const char *);
+    cchImportName = kHlpStrLen(pszImportName);
+    if (cchImportName < cchName)
+    {
+        kHlpMemCopy(pszName, pszImportName, cchImportName + 1);
+        rc = 0;
+    }
+    else
+    {
+        kHlpMemCopy(pszName, pszImportName, cchName);
+        if (cchName)
+            pszName[cchName - 1] = '\0';
+        rc = KERR_BUFFER_OVERFLOW;
+    }
+
+    return rc;
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo Implement import enumeration on darwin. */
+    (void)pModNative;
+    return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModNumberOfImports */
+static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits)
+{
+    PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+    /** @todo implement import counting on OS/2. */
+    (void)pModNative;
+    return -1;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    if (pModNative->cImportModules == ~(KU32)0)
+    {
+        /*
+         * We'll have to walk the import descriptors to figure out their number.
+         */
+        pModNative->cImportModules = 0;
+        if (    pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
+            &&  pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
+        {
+            const IMAGE_IMPORT_DESCRIPTOR  *pImpDesc;
+
+            pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
+                                              pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
+                                              const IMAGE_IMPORT_DESCRIPTOR *);
+            while (pImpDesc->Name && pImpDesc->FirstThunk)
+            {
+                pModNative->cImportModules++;
+                pImpDesc++;
+            }
+        }
+    }
+    return pModNative->cImportModules;
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo Implement import counting on Darwin. */
+    (void)pModNative;
+    return -1;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModGetStackInfo */
+static int kldrModNativeGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
+{
+    PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+    /** @todo implement stack info on OS/2. */
+    (void)pModNative;
+    return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    pStackInfo->Address = NIL_KLDRADDR;
+    pStackInfo->LinkAddress = NIL_KLDRADDR;
+    pStackInfo->cbStack = pStackInfo->cbStackThread = pModNative->pNtHdrs->OptionalHeader.SizeOfStackReserve;
+
+    return 0;
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo Implement stack info on Darwin. */
+    (void)pModNative;
+    return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModQueryMainEntrypoint */
+static int kldrModNativeQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
+{
+    PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+    /** @todo implement me on OS/2. */
+    (void)pModNative;
+    return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    /*
+     * Convert the address from the header.
+     */
+    *pMainEPAddress = pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint
+        ? BaseAddress + pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint
+        : NIL_KLDRADDR;
+    return 0;
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo Implement me on Darwin. */
+    (void)pModNative;
+    return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModEnumDbgInfo */
+static int kldrModNativeEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
+{
+    PKLDRMODNATIVE                  pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+    /** @todo implement me on OS/2. */
+    (void)pModNative;
+    return ERROR_NOT_SUPPORTED;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    const IMAGE_DEBUG_DIRECTORY    *pDbgDir;
+    KU32                            iDbgInfo;
+    KU32                            cb;
+    int                             rc;
+
+    /*
+     * Check that there is a debug directory first.
+     */
+    cb = pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+    if (    cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
+        ||  !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
+        return 0;
+
+    /*
+     * Enumerate the debug directory.
+     */
+    pDbgDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod,
+                                     pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
+                                     const IMAGE_DEBUG_DIRECTORY *);
+    for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
+    {
+        KLDRDBGINFOTYPE     enmDbgInfoType;
+
+        /* convert the type. */
+        switch (pDbgDir->Type)
+        {
+            case IMAGE_DEBUG_TYPE_UNKNOWN:
+            case IMAGE_DEBUG_TYPE_FPO:
+            case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
+            case IMAGE_DEBUG_TYPE_MISC:
+            case IMAGE_DEBUG_TYPE_EXCEPTION:
+            case IMAGE_DEBUG_TYPE_FIXUP:
+            case IMAGE_DEBUG_TYPE_BORLAND:
+            default:
+                enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
+                break;
+            case IMAGE_DEBUG_TYPE_CODEVIEW:
+                enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
+                break;
+        }
+
+        rc = pfnCallback(pMod, iDbgInfo,
+                         enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
+                         pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
+                         pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
+                         pDbgDir->SizeOfData,
+                         NULL,
+                         pvUser);
+        if (rc)
+            break;
+
+        /* next */
+        if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
+            break;
+    }
+
+    return rc;
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo Implement me on Darwin. */
+    (void)pModNative;
+    return KLDR_ERR_TODO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModHasDbgInfo */
+static int kldrModNativeHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
+{
+    PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+#if K_OS == K_OS_OS2
+
+    /** @todo implement me on OS/2. */
+    (void)pModNative;
+    return KLDR_ERR_NO_DEBUG_INFO;
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    /*
+     * Base this entirely on the presence of a debug directory.
+     */
+    if (    pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
+            < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
+        ||  !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
+        return KLDR_ERR_NO_DEBUG_INFO;
+    return 0;
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo Implement me on Darwin. */
+    (void)pModNative;
+    return KLDR_ERR_NO_DEBUG_INFO;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModMap */
+static int kldrModNativeMap(PKLDRMOD pMod)
+{
+    return 0;
+}
+
+
+/** @copydoc kLdrModUnmap */
+static int kldrModNativeUnmap(PKLDRMOD pMod)
+{
+    return 0;
+}
+
+
+/** @copydoc kLdrModAllocTLS */
+static int kldrModNativeAllocTLS(PKLDRMOD pMod)
+{
+    return 0;
+}
+
+
+/** @copydoc kLdrModFreeTLS */
+static void kldrModNativeFreeTLS(PKLDRMOD pMod)
+{
+}
+
+
+/** @copydoc kLdrModReload */
+static int kldrModNativeReload(PKLDRMOD pMod)
+{
+    return 0;
+}
+
+
+/** @copydoc kLdrModFixupMapping */
+static int kldrModNativeFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    return 0;
+}
+
+
+/** @copydoc kLdrModCallInit */
+static int kldrModNativeCallInit(PKLDRMOD pMod, KUPTR uHandle)
+{
+    return 0;
+}
+
+
+/** @copydoc kLdrModCallTerm */
+static int kldrModNativeCallTerm(PKLDRMOD pMod, KUPTR uHandle)
+{
+    return 0;
+}
+
+
+/** @copydoc kLdrModCallThread */
+static int kldrModNativeCallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
+{
+    return 0;
+}
+
+
+/** @copydoc kLdrModSize */
+static KLDRADDR kldrModNativeSize(PKLDRMOD pMod)
+{
+#if K_OS == K_OS_OS2
+    return 0; /* don't bother */
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    /* just because we can. */
+    PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData;
+    return pModNative->pNtHdrs->OptionalHeader.SizeOfImage;
+
+#elif K_OS == K_OS_DARWIN
+    /** @todo Implement me on Darwin. */
+    return 0;
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModGetBits */
+static int kldrModNativeGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+#if K_OS == K_OS_OS2
+    return ERROR_NOT_SUPPORTED; /* don't bother */
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */
+
+#elif K_OS == K_OS_DARWIN
+    return KLDR_ERR_TODO; /* don't bother. */
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/** @copydoc kLdrModRelocateBits */
+static int kldrModNativeRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                                     PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+#if K_OS == K_OS_OS2
+    return ERROR_NOT_SUPPORTED; /* don't bother */
+
+#elif K_OS == K_OS_WINDOWS || defined(__NT__)
+    return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */
+
+#elif K_OS == K_OS_DARWIN
+    return KLDR_ERR_TODO; /* don't bother. */
+
+#else
+# error "Port me"
+#endif
+}
+
+
+/**
+ * The native module interpreter method table.
+ */
+KLDRMODOPS g_kLdrModNativeOps =
+{
+    "Native",
+    NULL,
+    kldrModNativeCreate,
+    kldrModNativeDestroy,
+    kldrModNativeQuerySymbol,
+    kldrModNativeEnumSymbols,
+    kldrModNativeGetImport,
+    kldrModNativeNumberOfImports,
+    NULL /* can execute one is optional */,
+    kldrModNativeGetStackInfo,
+    kldrModNativeQueryMainEntrypoint,
+    NULL /* fixme */,
+    NULL /* fixme */,
+    kldrModNativeEnumDbgInfo,
+    kldrModNativeHasDbgInfo,
+    kldrModNativeMap,
+    kldrModNativeUnmap,
+    kldrModNativeAllocTLS,
+    kldrModNativeFreeTLS,
+    kldrModNativeReload,
+    kldrModNativeFixupMapping,
+    kldrModNativeCallInit,
+    kldrModNativeCallTerm,
+    kldrModNativeCallThread,
+    kldrModNativeSize,
+    kldrModNativeGetBits,
+    kldrModNativeRelocateBits,
+    NULL /* fixme */,
+    42 /* the end */
+};
+
Index: /trunk/kLdr/kLdrModPE.c
===================================================================
--- /trunk/kLdr/kLdrModPE.c	(revision 2)
+++ /trunk/kLdr/kLdrModPE.c	(revision 2)
@@ -0,0 +1,1989 @@
+/* $Id$ */
+/** @file
+ * kLdr - The Module Interpreter for the Portable Executable (PE) Format.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include "kLdrInternal.h"
+#include <k/kLdrFmts/pe.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRMODPE_STRICT
+ * Define KLDRMODPE_STRICT to enabled strict checks in KLDRMODPE. */
+#define KLDRMODPE_STRICT 1
+
+/** @def KLDRMODPE_ASSERT
+ * Assert that an expression is true when KLDR_STRICT is defined.
+ */
+#ifdef KLDRMODPE_STRICT
+# define KLDRMODPE_ASSERT(expr)  kHlpAssert(expr)
+#else
+# define KLDRMODPE_ASSERT(expr)  do {} while (0)
+#endif
+
+/** @def KLDRMODPE_RVA2TYPE
+ * Converts a RVA to a pointer of the specified type.
+ * @param   pvBits      The bits (image base).
+ * @param   uRVA        The image relative virtual address.
+ * @param   type        The type to cast to.
+ */
+#define KLDRMODPE_RVA2TYPE(pvBits, uRVA, type) \
+        ( (type) ((KUPTR)(pvBits) + (KUPTR)(uRVA)) )
+
+/** @def KLDRMODPE_VALID_RVA
+ * Checks that the specified RVA value is non-zero and within the bounds of the image.
+ * @returns true/false.
+ * @param   pModPE      The PE module interpreter instance.
+ * @param   uRVA        The RVA to validate.
+ */
+#define KLDRMODPE_VALID_RVA(pModPE, uRVA) \
+        ( (uRVA) && (uRVA) < (pModPE)->Hdrs.OptionalHeader.SizeOfImage )
+
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Instance data for the PE module interpreter.
+ */
+typedef struct KLDRMODPE
+{
+    /** Pointer to the module. (Follows the section table.) */
+    PKLDRMOD                pMod;
+    /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */
+    const void             *pvBits;
+    /** Pointer to the user mapping. */
+    const void             *pvMapping;
+    /** Reserved flags. */
+    KU32                    f32Reserved;
+    /** The number of imported modules.
+     * If ~(KU32)0 this hasn't been determined yet. */
+    KU32                    cImportModules;
+    /** The offset of the NT headers. */
+    KLDRFOFF                offHdrs;
+    /** Copy of the NT headers. */
+    IMAGE_NT_HEADERS64      Hdrs;
+    /** The section header table . */
+    IMAGE_SECTION_HEADER    aShdrs[1];
+} KLDRMODPE, *PKLDRMODPE;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits);
+static int  kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                                  PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+
+static int  kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppMod);
+/*static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg); */
+static int  kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE);
+static int  kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE);
+static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptionalHeader);
+static int  kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
+                                     PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser, PKLDRADDR puValue, KU32 *pfKind);
+static int  kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
+static int  kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
+                                    PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+static int  kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
+                                    PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+static int  kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
+static int  kldrModPEDoCallDLL(PKLDRMODPE pModPE, unsigned uOp, KUPTR uHandle);
+static int  kldrModPEDoCallTLS(PKLDRMODPE pModPE, unsigned uOp, KUPTR uHandle);
+static KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved);
+
+
+/**
+ * Create a loader module instance interpreting the executable image found
+ * in the specified file provider instance.
+ *
+ * @returns 0 on success and *ppMod pointing to a module instance.
+ *          On failure, a non-zero OS specific error code is returned.
+ * @param   pOps            Pointer to the registered method table.
+ * @param   pRdr            The file provider instance to use.
+ * @param   offNewHdr       The offset of the new header in MZ files. -1 if not found.
+ * @param   ppMod           Where to store the module instance pointer.
+ */
+static int kldrModPECreate(PCKLDRMODOPS pOps, PKRDR pRdr, KLDRFOFF offNewHdr, PPKLDRMOD ppMod)
+{
+    PKLDRMODPE pModPE;
+    int rc;
+
+    /*
+     * Create the instance data and do a minimal header validation.
+     */
+    rc = kldrModPEDoCreate(pRdr, offNewHdr, &pModPE);
+    if (!rc)
+    {
+        pModPE->pMod->pOps = pOps;
+        pModPE->pMod->u32Magic = KLDRMOD_MAGIC;
+        *ppMod = pModPE->pMod;
+        return 0;
+    }
+    kHlpFree(pModPE);
+    return rc;
+}
+
+
+/**
+ * Separate function for reading creating the PE module instance to
+ * simplify cleanup on failure.
+ */
+static int kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppModPE)
+{
+    struct
+    {
+        KU32                Signature;
+        IMAGE_FILE_HEADER   FileHdr;
+    } s;
+    PKLDRMODPE pModPE;
+    PKLDRMOD pMod;
+    KSIZE cb;
+    KSIZE cchFilename;
+    KLDRFOFF off;
+    KU32 i;
+    int rc;
+    *ppModPE = NULL;
+
+    /*
+     * Read the signature and file header.
+     */
+    rc = kRdrRead(pRdr, &s, sizeof(s), offNewHdr > 0 ? offNewHdr : 0);
+    if (rc)
+        return rc;
+    if (s.Signature != IMAGE_NT_SIGNATURE)
+        return KLDR_ERR_UNKNOWN_FORMAT;
+
+    /* sanity checks. */
+    if (    s.FileHdr.NumberOfSections > 4096
+        ||  (   s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32)
+             && s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64))
+        ||  !(s.FileHdr.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
+       )
+        return KLDR_ERR_PE_BAD_FILE_HEADER;
+    if (    s.FileHdr.Machine != IMAGE_FILE_MACHINE_I386
+        &&  s.FileHdr.Machine != IMAGE_FILE_MACHINE_AMD64
+       )
+        return KLDR_ERR_PE_UNSUPPORTED_MACHINE;
+
+    /*
+     * Calc the instance size, allocate and initialize it.
+     */
+    cchFilename = kHlpStrLen(kRdrName(pRdr));
+    cb = K_ALIGN_Z(K_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16)
+       + K_OFFSETOF(KLDRMOD, aSegments[s.FileHdr.NumberOfSections + 1])
+       + cchFilename + 1;
+    pModPE = (PKLDRMODPE)kHlpAlloc(cb);
+    if (!pModPE)
+        return KERR_NO_MEMORY;
+    *ppModPE = pModPE;
+
+    /* KLDRMOD */
+    pMod = (PKLDRMOD)((KU8 *)pModPE + K_ALIGN_Z(K_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16));
+    pMod->pvData = pModPE;
+    pMod->pRdr = pRdr;
+    pMod->pOps = NULL;      /* set upon success. */
+    pMod->cSegments = s.FileHdr.NumberOfSections + 1;
+    pMod->cchFilename = cchFilename;
+    pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
+    kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1);
+    pMod->pszName = kHlpGetFilename(pMod->pszFilename);
+    pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
+    switch (s.FileHdr.Machine)
+    {
+        case IMAGE_FILE_MACHINE_I386:
+            pMod->enmCpu = KCPU_I386;
+            pMod->enmArch = KCPUARCH_X86_32;
+            pMod->enmEndian = KLDRENDIAN_LITTLE;
+            break;
+
+        case IMAGE_FILE_MACHINE_AMD64:
+            pMod->enmCpu = KCPU_K8;
+            pMod->enmArch = KCPUARCH_AMD64;
+            pMod->enmEndian = KLDRENDIAN_LITTLE;
+            break;
+        default:
+            kHlpAssert(0);
+            break;
+    }
+    pMod->enmFmt = KLDRFMT_PE;
+    if (s.FileHdr.Characteristics & IMAGE_FILE_DLL)
+        pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+            ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
+            : KLDRTYPE_SHARED_LIBRARY_FIXED;
+    else
+        pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+            ? KLDRTYPE_EXECUTABLE_RELOCATABLE
+            : KLDRTYPE_EXECUTABLE_FIXED;
+    pMod->u32Magic = 0;     /* set upon success. */
+
+    /* KLDRMODPE */
+    pModPE->pMod = pMod;
+    pModPE->pvBits = NULL;
+    pModPE->pvMapping = NULL;
+    pModPE->f32Reserved = 0;
+    pModPE->cImportModules = ~(KU32)0;
+    pModPE->offHdrs = offNewHdr >= 0 ? offNewHdr : 0;
+    pModPE->Hdrs.Signature = s.Signature;
+    pModPE->Hdrs.FileHeader = s.FileHdr;
+
+    /*
+     * Read the optional header and the section table.
+     */
+    off = pModPE->offHdrs + sizeof(pModPE->Hdrs.Signature) + sizeof(pModPE->Hdrs.FileHeader);
+    rc = kRdrRead(pRdr, &pModPE->Hdrs.OptionalHeader, pModPE->Hdrs.FileHeader.SizeOfOptionalHeader, off);
+    if (rc)
+        return rc;
+    if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader != sizeof(pModPE->Hdrs.OptionalHeader))
+        kldrModPEDoOptionalHeaderConversion(&pModPE->Hdrs.OptionalHeader);
+    off += pModPE->Hdrs.FileHeader.SizeOfOptionalHeader;
+    rc = kRdrRead(pRdr, &pModPE->aShdrs[0], sizeof(IMAGE_SECTION_HEADER) * pModPE->Hdrs.FileHeader.NumberOfSections, off);
+    if (rc)
+        return rc;
+
+    /*
+     * Validate the two.
+     */
+    rc = kLdrModPEDoOptionalHeaderValidation(pModPE);
+    if (rc)
+        return rc;
+    for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
+    {
+        rc = kLdrModPEDoSectionHeadersValidation(pModPE);
+        if (rc)
+            return rc;
+    }
+
+    /*
+     * Setup the KLDRMOD segment array.
+     */
+    /* The implied headers section. */
+    pMod->aSegments[0].pvUser = NULL;
+    pMod->aSegments[0].pchName = "TheHeaders";
+    pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1;
+    pMod->aSegments[0].enmProt = KPROT_READONLY;
+    pMod->aSegments[0].cb = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
+    pMod->aSegments[0].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment;
+    pMod->aSegments[0].LinkAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
+    pMod->aSegments[0].offFile = 0;
+    pMod->aSegments[0].cbFile = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
+    pMod->aSegments[0].RVA = 0;
+    if (pMod->cSegments > 1)
+        pMod->aSegments[0].cbMapped = pModPE->aShdrs[0].VirtualAddress;
+    else
+        pMod->aSegments[0].cbMapped = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
+    pMod->aSegments[0].MapAddress = 0;
+
+    /* The section headers. */
+    for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
+    {
+        const char *pch;
+
+        /* unused */
+        pMod->aSegments[i + 1].pvUser = NULL;
+        pMod->aSegments[i + 1].MapAddress = 0;
+        pMod->aSegments[i + 1].SelFlat = 0;
+        pMod->aSegments[i + 1].Sel16bit = 0;
+        pMod->aSegments[i + 1].fFlags = 0;
+
+        /* name */
+        pMod->aSegments[i + 1].pchName = pch = (const char *)&pModPE->aShdrs[i].Name[0];
+        cb = IMAGE_SIZEOF_SHORT_NAME;
+        while (     cb > 0
+               &&   (pch[cb - 1] == ' ' || pch[cb - 1] == '\0'))
+            cb--;
+        pMod->aSegments[i + 1].cchName = cb;
+
+        /* size and addresses */
+        if (!(pModPE->aShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
+        {
+            pMod->aSegments[i + 1].cb          = pModPE->aShdrs[i].Misc.VirtualSize;
+            pMod->aSegments[i + 1].LinkAddress = pModPE->aShdrs[i].VirtualAddress
+                                               + pModPE->Hdrs.OptionalHeader.ImageBase;
+            pMod->aSegments[i + 1].RVA         = pModPE->aShdrs[i].VirtualAddress;
+            pMod->aSegments[i + 1].cbMapped    = pModPE->aShdrs[i].Misc.VirtualSize;
+            if (i + 2 < pMod->cSegments)
+                pMod->aSegments[i + 1].cbMapped= pModPE->aShdrs[i + 1].VirtualAddress
+                                               - pModPE->aShdrs[i].VirtualAddress;
+        }
+        else
+        {
+            pMod->aSegments[i + 1].cb          = 0;
+            pMod->aSegments[i + 1].cbMapped    = 0;
+            pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR;
+            pMod->aSegments[i + 1].RVA         = 0;
+        }
+
+        /* file location */
+        pMod->aSegments[i + 1].offFile = pModPE->aShdrs[i].PointerToRawData;
+        pMod->aSegments[i + 1].cbFile = pModPE->aShdrs[i].SizeOfRawData;
+        if (    pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */
+            &&  (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped)
+            pMod->aSegments[i + 1].cbFile = pMod->aSegments[i + 1].cbMapped;
+
+        /* protection */
+        switch (  pModPE->aShdrs[i].Characteristics
+                & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
+        {
+            case 0:
+            case IMAGE_SCN_MEM_SHARED:
+                pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS;
+                break;
+            case IMAGE_SCN_MEM_READ:
+            case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
+                pMod->aSegments[i + 1].enmProt = KPROT_READONLY;
+                break;
+            case IMAGE_SCN_MEM_WRITE:
+            case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
+                pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY;
+                break;
+            case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
+            case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
+                pMod->aSegments[i + 1].enmProt = KPROT_READWRITE;
+                break;
+            case IMAGE_SCN_MEM_EXECUTE:
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED:
+                pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE;
+                break;
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ:
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
+                pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ;
+                break;
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE:
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
+                pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY;
+                break;
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
+            case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
+                pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE;
+                break;
+        }
+
+        /* alignment. */
+        switch (pModPE->aShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
+        {
+            case 0: /* hope this is right... */
+                pMod->aSegments[i + 1].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment;
+                break;
+            case IMAGE_SCN_ALIGN_1BYTES:        pMod->aSegments[i + 1].Alignment = 1; break;
+            case IMAGE_SCN_ALIGN_2BYTES:        pMod->aSegments[i + 1].Alignment = 2; break;
+            case IMAGE_SCN_ALIGN_4BYTES:        pMod->aSegments[i + 1].Alignment = 4; break;
+            case IMAGE_SCN_ALIGN_8BYTES:        pMod->aSegments[i + 1].Alignment = 8; break;
+            case IMAGE_SCN_ALIGN_16BYTES:       pMod->aSegments[i + 1].Alignment = 16; break;
+            case IMAGE_SCN_ALIGN_32BYTES:       pMod->aSegments[i + 1].Alignment = 32; break;
+            case IMAGE_SCN_ALIGN_64BYTES:       pMod->aSegments[i + 1].Alignment = 64; break;
+            case IMAGE_SCN_ALIGN_128BYTES:      pMod->aSegments[i + 1].Alignment = 128; break;
+            case IMAGE_SCN_ALIGN_256BYTES:      pMod->aSegments[i + 1].Alignment = 256; break;
+            case IMAGE_SCN_ALIGN_512BYTES:      pMod->aSegments[i + 1].Alignment = 512; break;
+            case IMAGE_SCN_ALIGN_1024BYTES:     pMod->aSegments[i + 1].Alignment = 1024; break;
+            case IMAGE_SCN_ALIGN_2048BYTES:     pMod->aSegments[i + 1].Alignment = 2048; break;
+            case IMAGE_SCN_ALIGN_4096BYTES:     pMod->aSegments[i + 1].Alignment = 4096; break;
+            case IMAGE_SCN_ALIGN_8192BYTES:     pMod->aSegments[i + 1].Alignment = 8192; break;
+            default: kHlpAssert(0);          pMod->aSegments[i + 1].Alignment = 0; break;
+        }
+    }
+
+    /*
+     * We're done.
+     */
+    *ppModPE = pModPE;
+    return 0;
+}
+
+
+/**
+ * Converts a 32-bit optional header to a 64-bit one
+ *
+ * @param   pOptHdr     The optional header to convert.
+ */
+static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
+{
+    /* volatile everywhere! */
+    IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
+    IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
+    KU32 volatile                    *pu32Dst;
+    KU32 volatile                    *pu32Src;
+    KU32 volatile                    *pu32SrcLast;
+    KU32                              u32;
+
+    /* From LoaderFlags and out the difference is 4 * 32-bits. */
+    pu32Dst     = (KU32 *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
+    pu32Src     = (KU32 *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
+    pu32SrcLast = (KU32 *)&pOptHdr32->LoaderFlags;
+    while (pu32Src >= pu32SrcLast)
+        *pu32Dst-- = *pu32Src--;
+
+    /* The previous 4 fields are 32/64 and needs special attention. */
+    pOptHdr64->SizeOfHeapCommit   = pOptHdr32->SizeOfHeapCommit;
+    pOptHdr64->SizeOfHeapReserve  = pOptHdr32->SizeOfHeapReserve;
+    pOptHdr64->SizeOfStackCommit  = pOptHdr32->SizeOfStackCommit;
+    u32 = pOptHdr32->SizeOfStackReserve;
+    pOptHdr64->SizeOfStackReserve = u32;
+
+    /*
+     * The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version.
+     * Thus, ImageBase needs some special treatement. It will probably work fine assigning one to the
+     * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
+     */
+    u32 = pOptHdr32->ImageBase;
+    pOptHdr64->ImageBase = u32;
+}
+
+
+#if 0
+/**
+ * Converts a 32-bit load config directory to a 64 bit one.
+ *
+ * @param   pOptHdr     The load config to convert.
+ */
+static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
+{
+    /* volatile everywhere! */
+    IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
+    IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
+    KU32                                    u32;
+
+    pLoadCfg64->SEHandlerCount             = pLoadCfg32->SEHandlerCount;
+    pLoadCfg64->SEHandlerTable             = pLoadCfg32->SEHandlerTable;
+    pLoadCfg64->SecurityCookie             = pLoadCfg32->SecurityCookie;
+    pLoadCfg64->EditList                   = pLoadCfg32->EditList;
+    pLoadCfg64->Reserved1                  = pLoadCfg32->Reserved1;
+    pLoadCfg64->CSDVersion                 = pLoadCfg32->CSDVersion;
+    /* (ProcessHeapFlags switched place with ProcessAffinityMask, but we're
+     * more than 16 byte off by now so it doesn't matter.) */
+    pLoadCfg64->ProcessHeapFlags           = pLoadCfg32->ProcessHeapFlags;
+    pLoadCfg64->ProcessAffinityMask        = pLoadCfg32->ProcessAffinityMask;
+    pLoadCfg64->VirtualMemoryThreshold     = pLoadCfg32->VirtualMemoryThreshold;
+    pLoadCfg64->MaximumAllocationSize      = pLoadCfg32->MaximumAllocationSize;
+    pLoadCfg64->LockPrefixTable            = pLoadCfg32->LockPrefixTable;
+    pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
+    u32 = pLoadCfg32->DeCommitFreeBlockThreshold;
+    pLoadCfg64->DeCommitFreeBlockThreshold = u32;
+    /* the remainder matches. */
+}
+#endif
+
+
+/**
+ * Internal worker which validates the section headers.
+ */
+static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE)
+{
+    const unsigned fIs32Bit = pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32);
+
+    /* the magic */
+    if (    pModPE->Hdrs.OptionalHeader.Magic
+        !=  (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
+        return KLDR_ERR_PE_BAD_OPTIONAL_HEADER;
+
+    /** @todo validate more */
+    return 0;
+}
+
+
+/**
+ * Internal worker which validates the section headers.
+ */
+static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE)
+{
+    /** @todo validate shdrs */
+    return 0;
+}
+
+
+/** @copydoc KLDRMODOPS::pfnDestroy */
+static int kldrModPEDestroy(PKLDRMOD pMod)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+    int rc = 0;
+    KLDRMODPE_ASSERT(!pModPE->pvMapping);
+
+    if (pMod->pRdr)
+    {
+        rc = kRdrClose(pMod->pRdr);
+        pMod->pRdr = NULL;
+    }
+    pMod->u32Magic = 0;
+    pMod->pOps = NULL;
+    kHlpFree(pModPE);
+    return rc;
+}
+
+
+/**
+ * Performs the mapping of the image.
+ *
+ * This can be used to do the internal mapping as well as the
+ * user requested mapping. fForReal indicates which is desired.
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure.
+ * @param   pModPE          The interpreter module instance
+ * @param   fForReal        If set, do the user mapping. if clear, do the internal mapping.
+ */
+static int kldrModPEDoMap(PKLDRMODPE pModPE, unsigned fForReal)
+{
+    PKLDRMOD    pMod = pModPE->pMod;
+    KBOOL       fFixed;
+    void       *pvBase;
+    int         rc;
+    KU32        i;
+
+    /*
+     * Map it.
+     */
+    /* fixed image? */
+    fFixed = fForReal
+          && (   pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
+              || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED);
+    if (!fFixed)
+        pvBase = NULL;
+    else
+    {
+        pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress;
+        if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress)
+            return KLDR_ERR_ADDRESS_OVERFLOW;
+    }
+
+    /* try do the prepare */
+    rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
+    if (rc)
+        return rc;
+
+    /*
+     * Update the segments with their map addresses.
+     */
+    if (fForReal)
+    {
+        for (i = 0; i < pMod->cSegments; i++)
+        {
+            if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
+                pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA;
+        }
+        pModPE->pvMapping = pvBase;
+    }
+    else
+        pModPE->pvBits = pvBase;
+    return 0;
+}
+
+
+/**
+ * Unmaps a image mapping.
+ *
+ * This can be used to do the internal mapping as well as the
+ * user requested mapping. fForReal indicates which is desired.
+ *
+ * @returns 0 on success, non-zero OS or kLdr status code on failure.
+ * @param   pModPE          The interpreter module instance
+ * @param   pvMapping       The mapping to unmap.
+ */
+static int kldrModPEDoUnmap(PKLDRMODPE pModPE, const void *pvMapping)
+{
+    PKLDRMOD    pMod = pModPE->pMod;
+    int         rc;
+    KU32        i;
+
+    /*
+     * Try unmap the image.
+     */
+    rc = kRdrUnmap(pMod->pRdr, (void *)pvMapping, pMod->cSegments, pMod->aSegments);
+    if (rc)
+        return rc;
+
+    /*
+     * Update the segments to reflect that they aren't mapped any longer.
+     */
+    if (pModPE->pvMapping == pvMapping)
+    {
+        pModPE->pvMapping = NULL;
+        for (i = 0; i < pMod->cSegments; i++)
+            pMod->aSegments[i].MapAddress = 0;
+    }
+    if (pModPE->pvBits == pvMapping)
+        pModPE->pvBits = NULL;
+
+    return 0;
+}
+
+
+/**
+ * Gets usable bits and the right base address.
+ *
+ * @returns 0 on success.
+ * @returns A non-zero status code if the BaseAddress isn't right or some problem is encountered
+ *          featch in a temp mapping the bits.
+ * @param   pModPE          The interpreter module instance
+ * @param   ppvBits         The bits address, IN & OUT.
+ * @param   pBaseAddress    The base address, IN & OUT. Optional.
+ */
+static int kldrModPEBitsAndBaseAddress(PKLDRMODPE pModPE, const void **ppvBits, PKLDRADDR pBaseAddress)
+{
+    int rc = 0;
+
+    /*
+     * Correct the base address.
+     *
+     * We don't use the base address for interpreting the bits in this
+     * interpreter, which makes things relativly simple.
+     */
+    if (pBaseAddress)
+    {
+        if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
+            *pBaseAddress = pModPE->pMod->aSegments[0].MapAddress;
+        else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
+            *pBaseAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
+    }
+
+    /*
+     * Get bits.
+     */
+    if (ppvBits && !*ppvBits)
+    {
+        if (pModPE->pvMapping)
+            *ppvBits = pModPE->pvMapping;
+        else if (pModPE->pvBits)
+            *ppvBits = pModPE->pvBits;
+        else
+        {
+            /* create an internal mapping. */
+            rc = kldrModPEDoMap(pModPE, 0 /* not for real */);
+            if (rc)
+                return rc;
+            KLDRMODPE_ASSERT(pModPE->pvBits);
+            *ppvBits = pModPE->pvBits;
+        }
+    }
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModQuerySymbol */
+static int kldrModPEQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol,
+                                const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion,
+                                PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
+
+{
+    PKLDRMODPE                      pModPE = (PKLDRMODPE)pMod->pvData;
+    const KU32                     *paExportRVAs;
+    const IMAGE_EXPORT_DIRECTORY   *pExpDir;
+    KU32                            iExpOrd;
+    KU32                            uRVA;
+    int                             rc;
+
+    /*
+     * Make sure we've got mapped bits and resolve any base address aliases.
+     */
+    rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
+    if (rc)
+        return rc;
+    if (    pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
+        <   sizeof(IMAGE_EXPORT_DIRECTORY))
+        return KLDR_ERR_SYMBOL_NOT_FOUND;
+    if (pszVersion && *pszVersion)
+        return KLDR_ERR_SYMBOL_NOT_FOUND;
+
+    pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
+                                 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
+                                 PIMAGE_EXPORT_DIRECTORY);
+    if (!pchSymbol)
+    {
+        /*
+         * Simple, calculate the unbased ordinal and bounds check it.
+         */
+        iExpOrd = iSymbol - pExpDir->Base;
+        if (iExpOrd >= K_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions))
+            return KLDR_ERR_SYMBOL_NOT_FOUND;
+    }
+    else
+    {
+        /*
+         * Do a binary search for the name.
+         * (The name table is sorted in ascending ordered by the linker.)
+         */
+        const KU32 *paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const KU32 *);
+        const KU16 *paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const KU16 *);
+        KI32        iStart = 1; /* one based binary searching is simpler. */
+        KI32        iEnd = pExpDir->NumberOfNames;
+
+        for (;;)
+        {
+            KI32        i;
+            int         diff;
+            const char *pszName;
+
+            /* done? */
+            if (iStart > iEnd)
+            {
+#ifdef KLDRMODPE_STRICT /* Make sure the linker and we both did our job right. */
+                for (i = 0; i < (KI32)pExpDir->NumberOfNames; i++)
+
+                {
+                    pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i], const char *);
+                    KLDRMODPE_ASSERT(kHlpStrNComp(pszName, pchSymbol, cchSymbol) || pszName[cchSymbol]);
+                    KLDRMODPE_ASSERT(i == 0 || kHlpStrComp(pszName, KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)));
+                }
+#endif
+                return KLDR_ERR_SYMBOL_NOT_FOUND;
+            }
+
+            i = (iEnd - iStart) / 2 + iStart;
+            pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
+            diff = kHlpStrNComp(pszName, pchSymbol, cchSymbol);
+            if (!diff)
+                diff = pszName[cchSymbol] - 0;
+            if (diff < 0)
+                iStart = i + 1;     /* The symbol must be after the current name. */
+            else if (diff)
+                iEnd = i - 1;       /* The symbol must be before the current name. */
+            else
+            {
+                iExpOrd = paOrdinals[i - 1];    /* match! */
+                break;
+            }
+        }
+    }
+
+    /*
+     * Lookup the address in the 'symbol' table.
+     */
+    paExportRVAs = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const KU32 *);
+    uRVA = paExportRVAs[iExpOrd];
+    if (    uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
+        <   pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
+        return kldrModPEDoForwarderQuery(pModPE, pvBits, KLDRMODPE_RVA2TYPE(pvBits, uRVA, const char *),
+                                         pfnGetForwarder, pvUser, puValue, pfKind);
+
+    /*
+     * Set the return value.
+     */
+    if (puValue)
+        *puValue = BaseAddress + uRVA;
+    if (pfKind)
+        *pfKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
+                   ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
+                | KLDRSYMKIND_NO_TYPE;
+    return 0;
+}
+
+
+/**
+ * Deal with a forwarder entry.
+ *
+ * We do this seprately from kldrModPEQuerySymbol because the code is clumsy (as is all PE code
+ * thanks to the descriptive field names), and because it uses quite a bit more stack and we're
+ * trying to avoid allocating stack unless we have to.
+ *
+ * @returns See kLdrModQuerySymbol.
+ * @param   pModPE          The PE module interpreter instance.
+ * @param   pvBits          Where to read the image from.
+ * @param   pszForwarder    The forwarder entry name.
+ * @param   pfnGetForwarder The callback for resolving forwarder symbols. (optional)
+ * @param   pvUser          The user argument for the callback.
+ * @param   puValue         Where to put the value. (optional)
+ * @param   pfKind          Where to put the symbol kind. (optional)
+ */
+static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
+                                     PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind)
+{
+    const IMAGE_IMPORT_DESCRIPTOR *paImpDir;
+    KU32            iImpModule;
+    KU32            cchImpModule;
+    const char     *pszSymbol;
+    KU32            iSymbol;
+    int             rc;
+
+    if (!pfnGetForwarder)
+        return KLDR_ERR_FORWARDER_SYMBOL;
+
+    /*
+     * Separate the name into a module name and a symbol name or ordinal.
+     *
+     * The module name ends at the first dot ('.').
+     * After the dot follows either a symbol name or a hash ('#') + ordinal.
+     */
+    pszSymbol = pszForwarder;
+    while (*pszSymbol != '.')
+        pszSymbol++;
+    if (!*pszSymbol)
+        return KLDR_ERR_PE_BAD_FORWARDER;
+    cchImpModule = pszSymbol - pszForwarder;
+
+    pszSymbol++;                        /* skip the dot */
+    if (!*pszSymbol)
+        return KLDR_ERR_PE_BAD_FORWARDER;
+    if (*pszSymbol == '#')
+    {
+        unsigned uBase;
+        pszSymbol++;                    /* skip the hash */
+
+        /* base detection */
+        uBase = 10;
+        if (pszSymbol[0] == '0' &&  (pszSymbol[1] == 'x' || pszSymbol[1] == 'X'))
+        {
+            uBase = 16;
+            pszSymbol += 2;
+        }
+
+        /* ascii to integer */
+        iSymbol = 0;
+        for (;;)
+        {
+            /* convert char to digit. */
+            unsigned uDigit = *pszSymbol++;
+            if (uDigit >= '0' && uDigit <= '9')
+                uDigit -= '0';
+            else if (uDigit >= 'a' && uDigit <= 'z')
+                uDigit -= 'a' + 10;
+            else if (uDigit >= 'A' && uDigit <= 'Z')
+                uDigit -= 'A' + 10;
+            else if (!uDigit)
+                break;
+            else
+                return KLDR_ERR_PE_BAD_FORWARDER;
+            if (uDigit >= uBase)
+                return KLDR_ERR_PE_BAD_FORWARDER;
+
+            /* insert the digit */
+            iSymbol *= uBase;
+            iSymbol += uDigit;
+        }
+
+        pszSymbol = NULL;               /* no symbol name. */
+    }
+    else
+        iSymbol = NIL_KLDRMOD_SYM_ORDINAL; /* no ordinal number. */
+
+
+    /*
+     * Find the import module name.
+     *
+     * We ASSUME the linker will make sure there is an import
+     * entry for the module... not sure if this is right though.
+     */
+    if (    !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
+        ||  !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
+        return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
+    paImpDir = KLDRMODPE_RVA2TYPE(pvBits,
+                                  pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
+                                  const IMAGE_IMPORT_DESCRIPTOR *);
+
+    kldrModPENumberOfImports(pModPE->pMod, pvBits);
+    for (iImpModule = 0; iImpModule < pModPE->cImportModules; iImpModule++)
+    {
+        const char *pszName = KLDRMODPE_RVA2TYPE(pvBits, paImpDir[iImpModule].Name, const char *);
+        KSIZE       cchName = kHlpStrLen(pszName);
+        if (    (   cchName == cchImpModule
+                 || (   cchName > cchImpModule
+                     && pszName[cchImpModule] == '.'
+                     && (pszName[cchImpModule + 1] == 'd' || pszName[cchImpModule + 1] == 'D')
+                     && (pszName[cchImpModule + 2] == 'l' || pszName[cchImpModule + 2] == 'L')
+                     && (pszName[cchImpModule + 3] == 'l' || pszName[cchImpModule + 3] == 'L'))
+                )
+            &&  kHlpMemICompAscii(pszName, pszForwarder, cchImpModule)
+           )
+        {
+            /*
+             * Now the rest is up to the callback (almost).
+             */
+            rc = pfnGetForwarder(pModPE->pMod, iImpModule, iSymbol, pszSymbol,
+                                 pszSymbol ? kHlpStrLen(pszSymbol) : 0, NULL, puValue, pfKind, pvUser);
+            if (!rc && pfKind)
+                *pfKind |= KLDRSYMKIND_FORWARDER;
+            return rc;
+        }
+    }
+    return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
+}
+
+
+/** @copydoc kLdrModEnumSymbols */
+static int kldrModPEEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
+                                KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
+{
+    PKLDRMODPE                      pModPE = (PKLDRMODPE)pMod->pvData;
+    const KU32                     *paFunctions;
+    const IMAGE_EXPORT_DIRECTORY   *pExpDir;
+    const KU32                     *paRVANames;
+    const KU16                     *paOrdinals;
+    KU32                            iFunction;
+    KU32                            cFunctions;
+    KU32                            cNames;
+    int                             rc;
+
+    /*
+     * Make sure we've got mapped bits and resolve any base address aliases.
+     */
+    rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
+    if (rc)
+        return rc;
+
+    if (    pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
+        <   sizeof(IMAGE_EXPORT_DIRECTORY))
+        return 0; /* no exports to enumerate, return success. */
+
+    pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
+                                 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
+                                 PIMAGE_EXPORT_DIRECTORY);
+
+    /*
+     * Enumerate the ordinal exports.
+     */
+    paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const KU32 *);
+    paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const KU16 *);
+    paFunctions = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const KU32 *);
+    cFunctions = pExpDir->NumberOfFunctions;
+    cNames = pExpDir->NumberOfNames;
+    for (iFunction = 0; iFunction < cFunctions; iFunction++)
+    {
+        unsigned        fFoundName;
+        KU32            iName;
+        const KU32      uRVA = paFunctions[iFunction];
+        const KLDRADDR  uValue = BaseAddress + uRVA;
+        KU32            fKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
+                              ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
+                              | KLDRSYMKIND_NO_TYPE;
+        if (    uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
+            <   pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
+            fKind |= KLDRSYMKIND_FORWARDER;
+
+        /*
+         * Any symbol names?
+         */
+        fFoundName = 0;
+        for (iName = 0; iName < cNames; iName++)
+        {
+            const char *pszName;
+            if (paOrdinals[iName] != iFunction)
+                continue;
+            fFoundName = 1;
+            pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[iName], const char *);
+            rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, kHlpStrLen(pszName), NULL,
+                             uValue, fKind, pvUser);
+            if (rc)
+                return rc;
+        }
+
+        /*
+         * If no names, call once with the ordinal only.
+         */
+        if (!fFoundName)
+        {
+            rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser);
+            if (rc)
+                return rc;
+        }
+    }
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModGetImport */
+static int kldrModPEGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName)
+{
+    PKLDRMODPE                      pModPE = (PKLDRMODPE)pMod->pvData;
+    const IMAGE_IMPORT_DESCRIPTOR  *pImpDesc;
+    const char                     *pszImportName;
+    KSIZE                           cchImportName;
+    int                             rc;
+
+    /*
+     * Make sure we've got mapped bits and resolve any base address aliases.
+     */
+    rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
+    if (rc)
+        return rc;
+
+    /*
+     * Simple bounds check.
+     */
+    if (iImport >= (KU32)kldrModPENumberOfImports(pMod, pvBits))
+        return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
+
+    /*
+     * Get the name.
+     */
+    pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
+                                  pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
+                                  + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport,
+                                  const IMAGE_IMPORT_DESCRIPTOR *);
+    pszImportName = KLDRMODPE_RVA2TYPE(pvBits, pImpDesc->Name, const char *);
+    cchImportName = kHlpStrLen(pszImportName);
+    if (cchImportName < cchName)
+    {
+        kHlpMemCopy(pszName, pszImportName, cchImportName + 1);
+        rc = 0;
+    }
+    else
+    {
+        kHlpMemCopy(pszName, pszImportName, cchName);
+        if (cchName)
+            pszName[cchName - 1] = '\0';
+        rc = KERR_BUFFER_OVERFLOW;
+    }
+
+    return rc;
+}
+
+
+/** @copydoc kLdrModNumberOfImports */
+static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+    if (pModPE->cImportModules == ~(KU32)0)
+    {
+        /*
+         * We'll have to walk the import descriptors to figure out their number.
+         * First, make sure we've got mapped bits.
+         */
+        if (kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL))
+            return -1;
+        pModPE->cImportModules = 0;
+        if (    pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
+            &&  pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
+        {
+            const IMAGE_IMPORT_DESCRIPTOR  *pImpDesc;
+
+            pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
+                                          pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
+                                          const IMAGE_IMPORT_DESCRIPTOR *);
+            while (pImpDesc->Name && pImpDesc->FirstThunk)
+            {
+                pModPE->cImportModules++;
+                pImpDesc++;
+            }
+        }
+    }
+    return pModPE->cImportModules;
+}
+
+
+/** @copydoc kLdrModGetStackInfo */
+static int kldrModPEGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+
+    pStackInfo->Address = NIL_KLDRADDR;
+    pStackInfo->LinkAddress = NIL_KLDRADDR;
+    pStackInfo->cbStack = pStackInfo->cbStackThread = pModPE->Hdrs.OptionalHeader.SizeOfStackReserve;
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModQueryMainEntrypoint */
+static int kldrModPEQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+    int rc;
+
+    /*
+     * Resolve base address alias if any.
+     */
+    rc = kldrModPEBitsAndBaseAddress(pModPE, NULL, &BaseAddress);
+    if (rc)
+        return rc;
+
+    /*
+     * Convert the address from the header.
+     */
+    *pMainEPAddress = pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
+        ? BaseAddress + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
+        : NIL_KLDRADDR;
+    return 0;
+}
+
+
+/** @copydoc kLdrModEnumDbgInfo */
+static int kldrModPEEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
+{
+    PKLDRMODPE                      pModPE = (PKLDRMODPE)pMod->pvData;
+    const IMAGE_DEBUG_DIRECTORY    *pDbgDir;
+    KU32                            iDbgInfo;
+    KU32                            cb;
+    int                             rc;
+
+    /*
+     * Check that there is a debug directory first.
+     */
+    cb = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+    if (    cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
+        ||  !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
+        return 0;
+
+    /*
+     * Make sure we've got mapped bits.
+     */
+    rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
+    if (rc)
+        return rc;
+
+    /*
+     * Enumerate the debug directory.
+     */
+    pDbgDir = KLDRMODPE_RVA2TYPE(pvBits,
+                                 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
+                                 const IMAGE_DEBUG_DIRECTORY *);
+    for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
+    {
+        KLDRDBGINFOTYPE     enmDbgInfoType;
+
+        /* convert the type. */
+        switch (pDbgDir->Type)
+        {
+            case IMAGE_DEBUG_TYPE_UNKNOWN:
+            case IMAGE_DEBUG_TYPE_FPO:
+            case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
+            case IMAGE_DEBUG_TYPE_MISC:
+            case IMAGE_DEBUG_TYPE_EXCEPTION:
+            case IMAGE_DEBUG_TYPE_FIXUP:
+            case IMAGE_DEBUG_TYPE_BORLAND:
+            default:
+                enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
+                break;
+            case IMAGE_DEBUG_TYPE_CODEVIEW:
+                enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
+                break;
+        }
+
+        rc = pfnCallback(pMod, iDbgInfo,
+                         enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
+                         pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
+                         pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
+                         pDbgDir->SizeOfData,
+                         NULL,
+                         pvUser);
+        if (rc)
+            break;
+
+        /* next */
+        if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
+            break;
+    }
+
+    return rc;
+}
+
+
+/** @copydoc kLdrModHasDbgInfo */
+static int kldrModPEHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+
+    /*
+     * Base this entirely on the presence of a debug directory.
+     */
+    if (    pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
+            < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
+        ||  !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
+        return KLDR_ERR_NO_DEBUG_INFO;
+    return 0;
+}
+
+
+/** @copydoc kLdrModMap */
+static int kldrModPEMap(PKLDRMOD pMod)
+{
+    PKLDRMODPE  pModPE = (PKLDRMODPE)pMod->pvData;
+    int         rc;
+
+    /*
+     * Already mapped?
+     */
+    if (pModPE->pvMapping)
+        return KLDR_ERR_ALREADY_MAPPED;
+
+    /*
+     * We've got a common worker which does this.
+     */
+    rc = kldrModPEDoMap(pModPE, 1 /* the real thing */);
+    if (rc)
+        return rc;
+    KLDRMODPE_ASSERT(pModPE->pvMapping);
+    return 0;
+}
+
+
+/** @copydoc kLdrModUnmap */
+static int kldrModPEUnmap(PKLDRMOD pMod)
+{
+    PKLDRMODPE  pModPE = (PKLDRMODPE)pMod->pvData;
+    int         rc;
+
+    /*
+     * Mapped?
+     */
+    if (!pModPE->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * We've got a common worker which does this.
+     */
+    rc = kldrModPEDoUnmap(pModPE, pModPE->pvMapping);
+    if (rc)
+        return rc;
+    KLDRMODPE_ASSERT(!pModPE->pvMapping);
+    return 0;
+
+}
+
+
+/** @copydoc kLdrModAllocTLS */
+static int kldrModPEAllocTLS(PKLDRMOD pMod)
+{
+    PKLDRMODPE  pModPE = (PKLDRMODPE)pMod->pvData;
+
+    /*
+     * Mapped?
+     */
+    if (!pModPE->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * If no TLS directory then there is nothing to do.
+     */
+    if (    !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
+        ||  !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
+        return 0;
+    /** @todo implement TLS. */
+    return -1;
+}
+
+
+/** @copydoc kLdrModFreeTLS */
+static void kldrModPEFreeTLS(PKLDRMOD pMod)
+{
+    PKLDRMODPE  pModPE = (PKLDRMODPE)pMod->pvData;
+
+    /*
+     * Mapped?
+     */
+    if (!pModPE->pvMapping)
+        return;
+
+    /*
+     * If no TLS directory then there is nothing to do.
+     */
+    if (    !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
+        ||  !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
+        return;
+    /** @todo implement TLS. */
+    return;
+}
+
+
+/** @copydoc kLdrModReload */
+static int kldrModPEReload(PKLDRMOD pMod)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+
+    /*
+     * Mapped?
+     */
+    if (!pModPE->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /* the file provider does it all */
+    return kRdrRefresh(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments);
+}
+
+
+/** @copydoc kLdrModFixupMapping */
+static int kldrModPEFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+    int rc, rc2;
+
+    /*
+     * Mapped?
+     */
+    if (!pModPE->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Before doing anything we'll have to make all pages writable.
+     */
+    rc = kRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
+    if (rc)
+        return rc;
+
+    /*
+     * Apply base relocations.
+     */
+    rc = kldrModPEDoFixups(pModPE, (void *)pModPE->pvMapping, (KUPTR)pModPE->pvMapping,
+                           pModPE->Hdrs.OptionalHeader.ImageBase);
+
+    /*
+     * Resolve imports.
+     */
+    if (!rc)
+        rc = kldrModPEDoImports(pModPE, (void *)pModPE->pvMapping, pfnGetImport, pvUser);
+
+    /*
+     * Restore protection.
+     */
+    rc2 = kRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
+    if (!rc && rc2)
+        rc = rc2;
+    return rc;
+}
+
+
+/**
+ * Applies base relocations to a (unprotected) image mapping.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModPE          The PE module interpreter instance.
+ * @param   pvMapping       The mapping to fixup.
+ * @param   NewBaseAddress  The address to fixup the mapping to.
+ * @param   OldBaseAddress  The address the mapping is currently fixed up to.
+ */
+static int  kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress)
+{
+    const KLDRADDR                  Delta = NewBaseAddress - OldBaseAddress;
+    KU32                            cbLeft = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
+    const IMAGE_BASE_RELOCATION    *pBR, *pFirstBR;
+
+    /*
+     * Don't don anything if the delta is 0 or there aren't any relocations.
+     */
+    if (    !Delta
+        ||  !cbLeft
+        ||  !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
+        return 0;
+
+    /*
+     * Process the fixups block by block.
+     * (These blocks appears to be 4KB on all archs despite the native page size.)
+     */
+    pBR = pFirstBR = KLDRMODPE_RVA2TYPE(pvMapping,
+                                        pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
+                                        const IMAGE_BASE_RELOCATION *);
+    while (     cbLeft > sizeof(IMAGE_BASE_RELOCATION)
+           &&   pBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION) /* paranoia */)
+    {
+        union
+        {
+            KU8        *pu8;
+            KU16       *pu16;
+            KU32       *pu32;
+            KU64       *pu64;
+        }               uChunk,
+                        u;
+        const KU16 *poffFixup = (const KU16 *)(pBR + 1);
+        const KU32  cbBlock = K_MIN(cbLeft, pBR->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION); /* more caution... */
+        KU32        cFixups = cbBlock / sizeof(poffFixup[0]);
+        uChunk.pu8 = KLDRMODPE_RVA2TYPE(pvMapping, pBR->VirtualAddress, KU8 *);
+
+        /*
+         * Loop thru the fixups in this chunk.
+         */
+        while (cFixups > 0)
+        {
+            u.pu8 = uChunk.pu8 + (*poffFixup & 0xfff);
+            switch (*poffFixup >> 12) /* ordered by value. */
+            {
+                /* 0 - Alignment placeholder. */
+                case IMAGE_REL_BASED_ABSOLUTE:
+                    break;
+
+                /* 1 - 16-bit, add 2nd 16-bit part of the delta. (rare) */
+                case IMAGE_REL_BASED_HIGH:
+                    *u.pu16 += (KU16)(Delta >> 16);
+                    break;
+
+                /* 2 - 16-bit, add 1st 16-bit part of the delta. (rare) */
+                case IMAGE_REL_BASED_LOW:
+                    *u.pu16 += (KU16)Delta;
+                    break;
+
+                /* 3 - 32-bit, add delta. (frequent in 32-bit images) */
+                case IMAGE_REL_BASED_HIGHLOW:
+                    *u.pu32 += (KU32)Delta;
+                    break;
+
+                /* 4 - 16-bit, add 2nd 16-bit of the delta, sign adjust for the lower 16-bit. one arg. (rare)  */
+                case IMAGE_REL_BASED_HIGHADJ:
+                {
+                    KI32 i32;
+                    if (cFixups <= 1)
+                        return KLDR_ERR_PE_BAD_FIXUP;
+
+                    i32 = (KU32)*u.pu16 << 16;
+                    i32 |= *++poffFixup; cFixups--; /* the addend argument */
+                    i32 += (KU32)Delta;
+                    i32 += 0x8000;
+                    *u.pu16 = (KU16)(i32 >> 16);
+                    break;
+                }
+
+                /* 5 - 32-bit MIPS JMPADDR, no implemented. */
+                case IMAGE_REL_BASED_MIPS_JMPADDR:
+                    *u.pu32 = (*u.pu32 & 0xc0000000)
+                            | ((KU32)((*u.pu32 << 2) + (KU32)Delta) >> 2);
+                    break;
+
+                /* 6 - Intra section? Reserved value in later specs. Not implemented. */
+                case IMAGE_REL_BASED_SECTION:
+                    KLDRMODPE_ASSERT(!"SECTION");
+                    return KLDR_ERR_PE_BAD_FIXUP;
+
+                /* 7 - Relative intra section? Reserved value in later specs. Not implemented. */
+                case IMAGE_REL_BASED_REL32:
+                    KLDRMODPE_ASSERT(!"SECTION");
+                    return KLDR_ERR_PE_BAD_FIXUP;
+
+                /* 8 - reserved according to binutils... */
+                case 8:
+                    KLDRMODPE_ASSERT(!"RESERVERED8");
+                    return KLDR_ERR_PE_BAD_FIXUP;
+
+                /* 9 - IA64_IMM64 (/ MIPS_JMPADDR16), no specs nor need to support the platform yet.
+                 * Bet this requires more code than all the other fixups put together in good IA64 spirit :-) */
+                case IMAGE_REL_BASED_IA64_IMM64:
+                    KLDRMODPE_ASSERT(!"IA64_IMM64 / MIPS_JMPADDR16");
+                    return KLDR_ERR_PE_BAD_FIXUP;
+
+                /* 10 - 64-bit, add delta. (frequently in 64-bit images) */
+                case IMAGE_REL_BASED_DIR64:
+                    *u.pu64 += (KU64)Delta;
+                    break;
+
+                /* 11 - 16-bit, add 3rd 16-bit of the delta, sign adjust for the lower 32-bit. two args. (rare) */
+                case IMAGE_REL_BASED_HIGH3ADJ:
+                {
+                    KI64 i64;
+                    if (cFixups <= 2)
+                        return KLDR_ERR_PE_BAD_FIXUP;
+
+                    i64 = (KU64)*u.pu16 << 32
+                        | ((KU32)poffFixup[2] << 16)
+                        | poffFixup[1];
+                    i64 += Delta;
+                    i64 += 0x80008000UL;
+                    *u.pu16 = (KU16)(i64 >> 32);
+                    /* skip the addends arguments */
+                    poffFixup += 2;
+                    cFixups -= 2;
+                    break;
+                }
+
+                /* the rest are yet to be defined.*/
+                default:
+                    return KLDR_ERR_PE_BAD_FIXUP;
+            }
+
+            /*
+             * Next relocation.
+             */
+            poffFixup++;
+            cFixups--;
+        }
+
+
+        /*
+         * Next block.
+         */
+        cbLeft -= pBR->SizeOfBlock;
+        pBR = (PIMAGE_BASE_RELOCATION)((KUPTR)pBR + pBR->SizeOfBlock);
+    }
+
+    return 0;
+}
+
+
+
+/**
+ * Resolves imports.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModPE          The PE module interpreter instance.
+ * @param   pvMapping       The mapping which imports should be resolved.
+ * @param   pfnGetImport    The callback for resolving an imported symbol.
+ * @param   pvUser          User argument to the callback.
+ */
+static int  kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
+
+    /*
+     * If no imports, there is nothing to do.
+     */
+    kldrModPENumberOfImports(pModPE->pMod, pvMapping);
+    if (!pModPE->cImportModules)
+        return 0;
+
+    pImpDesc = KLDRMODPE_RVA2TYPE(pvMapping,
+                                  pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
+                                  const IMAGE_IMPORT_DESCRIPTOR *);
+    if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
+        return kldrModPEDoImports32Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser);
+    return kldrModPEDoImports64Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser);
+}
+
+
+/**
+ * Resolves imports, 32-bit image.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModPE          The PE module interpreter instance.
+ * @param   pvMapping       The mapping which imports should be resolved.
+ * @param   pImpDesc        Pointer to the first import descriptor.
+ * @param   pfnGetImport    The callback for resolving an imported symbol.
+ * @param   pvUser          User argument to the callback.
+ */
+static int  kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
+                                    PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMOD pMod = pModPE->pMod;
+    KU32 iImp;
+
+    /*
+     * Iterate the import descriptors.
+     */
+    for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++)
+    {
+        PIMAGE_THUNK_DATA32         pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA32);
+        const IMAGE_THUNK_DATA32   *pThunk = pImpDesc->u.OriginalFirstThunk
+            ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA32 *)
+            : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA32 *);
+
+        /* Iterate the thunks. */
+        while (pThunk->u1.Ordinal != 0)
+        {
+            KLDRADDR    Value;
+            KU32        fKind = KLDRSYMKIND_REQ_FLAT;
+            int         rc;
+
+            /* Ordinal or name import? */
+            if (IMAGE_SNAP_BY_ORDINAL32(pThunk->u1.Ordinal))
+                rc = pfnGetImport(pMod, iImp, IMAGE_ORDINAL32(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser);
+            else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal))
+            {
+                const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *);
+                rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name,
+                                  kHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser);
+            }
+            else
+            {
+                KLDRMODPE_ASSERT(!"bad 32-bit import");
+                return KLDR_ERR_PE_BAD_IMPORT;
+            }
+            if (rc)
+                return rc;
+
+            /* Apply it. */
+            pFirstThunk->u1.Function = (KU32)Value;
+            if (pFirstThunk->u1.Function != Value)
+            {
+                KLDRMODPE_ASSERT(!"overflow");
+                return KLDR_ERR_ADDRESS_OVERFLOW;
+            }
+
+            /* next */
+            pThunk++;
+            pFirstThunk++;
+        }
+    }
+
+    return 0;
+}
+
+
+/**
+ * Resolves imports, 64-bit image.
+ *
+ * @returns 0 on success, non-zero kLdr status code on failure.
+ * @param   pModPE          The PE module interpreter instance.
+ * @param   pvMapping       The mapping which imports should be resolved.
+ * @param   pImpDesc        Pointer to the first import descriptor.
+ * @param   pfnGetImport    The callback for resolving an imported symbol.
+ * @param   pvUser          User argument to the callback.
+ */
+static int  kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
+                                    PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMOD pMod = pModPE->pMod;
+    KU32 iImp;
+
+    /*
+     * Iterate the import descriptors.
+     */
+    for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++)
+    {
+        PIMAGE_THUNK_DATA64         pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA64);
+        const IMAGE_THUNK_DATA64   *pThunk = pImpDesc->u.OriginalFirstThunk
+            ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA64 *)
+            : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA64 *);
+
+        /* Iterate the thunks. */
+        while (pThunk->u1.Ordinal != 0)
+        {
+            KLDRADDR    Value;
+            KU32        fKind = KLDRSYMKIND_REQ_FLAT;
+            int         rc;
+
+            /* Ordinal or name import? */
+            if (IMAGE_SNAP_BY_ORDINAL64(pThunk->u1.Ordinal))
+                rc = pfnGetImport(pMod, iImp, (KU32)IMAGE_ORDINAL64(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser);
+            else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal))
+            {
+                const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *);
+                rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name,
+                                  kHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser);
+            }
+            else
+            {
+                KLDRMODPE_ASSERT(!"bad 64-bit import");
+                return KLDR_ERR_PE_BAD_IMPORT;
+            }
+            if (rc)
+                return rc;
+
+            /* Apply it. */
+            pFirstThunk->u1.Function = Value;
+
+            /* next */
+            pThunk++;
+            pFirstThunk++;
+        }
+    }
+
+    return 0;
+}
+
+
+
+/** @copydoc kLdrModCallInit */
+static int kldrModPECallInit(PKLDRMOD pMod, KUPTR uHandle)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+    int rc;
+
+    /*
+     * Mapped?
+     */
+    if (!pModPE->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Do TLS callbacks first and then call the init/term function if it's a DLL.
+     */
+    rc = kldrModPEDoCallTLS(pModPE, DLL_PROCESS_ATTACH, uHandle);
+    if (    !rc
+        &&  (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL))
+    {
+        rc = kldrModPEDoCallDLL(pModPE, DLL_PROCESS_ATTACH, uHandle);
+        if (rc)
+            kldrModPEDoCallTLS(pModPE, DLL_PROCESS_DETACH, uHandle);
+    }
+
+    return rc;
+}
+
+
+/**
+ * Call the DLL entrypoint.
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_MODULE_INIT_FAILED  or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
+ * @param   pModPE          The PE module interpreter instance.
+ * @param   uOp             The operation (DLL_*).
+ * @param   uHandle         The module handle to present.
+ */
+static int  kldrModPEDoCallDLL(PKLDRMODPE pModPE, unsigned uOp, KUPTR uHandle)
+{
+    int rc;
+
+    /*
+     * If no entrypoint there isn't anything to be done.
+     */
+    if (!pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint)
+        return 0;
+
+    /*
+     * Invoke the entrypoint and convert the boolean result to a kLdr status code.
+     */
+    rc = kldrModPEDoCall((KUPTR)pModPE->pvMapping + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint,
+                         uHandle, uOp, NULL);
+    if (rc)
+        rc = 0;
+    else if (uOp == DLL_PROCESS_ATTACH)
+        rc = KLDR_ERR_MODULE_INIT_FAILED;
+    else if (uOp == DLL_THREAD_ATTACH)
+        rc = KLDR_ERR_THREAD_ATTACH_FAILED;
+    else /* detach: ignore failures */
+        rc = 0;
+    return rc;
+}
+
+
+/**
+ * Call the TLS entrypoints.
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_THREAD_ATTACH_FAILED on failure.
+ * @param   pModPE          The PE module interpreter instance.
+ * @param   uOp             The operation (DLL_*).
+ * @param   uHandle         The module handle to present.
+ */
+static int  kldrModPEDoCallTLS(PKLDRMODPE pModPE, unsigned uOp, KUPTR uHandle)
+{
+    /** @todo implement TLS support. */
+    return 0;
+}
+
+
+/**
+ * Do a 3 parameter callback.
+ *
+ * @returns 32-bit callback return.
+ * @param   uEntrypoint     The address of the function to be called.
+ * @param   uHandle         The first argument, the module handle.
+ * @param   uOp             The second argumnet, the reason we're calling.
+ * @param   pvReserved      The third argument, reserved argument. (figure this one out)
+ */
+static KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved)
+{
+    KI32 rc;
+
+/** @todo try/except */
+#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
+    /*
+     * Be very careful.
+     * Not everyone will have got the calling convention right.
+     */
+# ifdef __GNUC__
+    __asm__ __volatile__(
+        "pushl  %2\n\t"
+        "pushl  %1\n\t"
+        "pushl  %0\n\t"
+        "lea   12(%%esp), %2\n\t"
+        "call  *%3\n\t"
+        "movl   %2, %%esp\n\t"
+        : "=a" (rc)
+        : "d" (uOp),
+          "S" (0),
+          "c" (uEntrypoint),
+          "0" (uHandle));
+# elif defined(_MSC_VER)
+    __asm {
+        mov     eax, [uHandle]
+        mov     edx, [uOp]
+        mov     ecx, 0
+        mov     ebx, [uEntrypoint]
+        push    edi
+        mov     edi, esp
+        push    ecx
+        push    edx
+        push    eax
+        call    ebx
+        mov     esp, edi
+        pop     edi
+        mov     [rc], eax
+    }
+# else
+#  error "port me!"
+# endif
+
+#elif defined(__AMD64__) || defined(__x86_64__) || defined(_M_IX86)
+    /*
+     * For now, let's just get the work done...
+     */
+    /** @todo Deal with GCC / MSC differences in some sensible way. */
+    int (*pfn)(KUPTR uHandle, KU32 uOp, void *pvReserved);
+    pfn = (int (*)(KUPTR uHandle, KU32 uOp, void *pvReserved))uEntrypoint;
+    rc = pfn(uHandle, uOp, NULL);
+
+#else
+# error "port me"
+#endif
+
+    return rc;
+}
+
+
+/** @copydoc kLdrModCallTerm */
+static int kldrModPECallTerm(PKLDRMOD pMod, KUPTR uHandle)
+{
+    PKLDRMODPE  pModPE = (PKLDRMODPE)pMod->pvData;
+
+    /*
+     * Mapped?
+     */
+    if (!pModPE->pvMapping)
+        return KLDR_ERR_NOT_MAPPED;
+
+    /*
+     * Do TLS callbacks first.
+     */
+    kldrModPEDoCallTLS(pModPE, DLL_PROCESS_DETACH, uHandle);
+    if (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL)
+        kldrModPEDoCallDLL(pModPE, DLL_PROCESS_DETACH, uHandle);
+
+    return 0;
+}
+
+
+/** @copydoc kLdrModCallThread */
+static int kldrModPECallThread(PKLDRMOD pMod, KUPTR uHandle, unsigned fAttachingOrDetaching)
+{
+    PKLDRMODPE  pModPE = (PKLDRMODPE)pMod->pvData;
+    unsigned    uOp = fAttachingOrDetaching ? DLL_THREAD_ATTACH : DLL_THREAD_DETACH;
+    int         rc;
+
+    /*
+     * Do TLS callbacks first and then call the init/term function if it's a DLL.
+     */
+    rc = kldrModPEDoCallTLS(pModPE, uOp, uHandle);
+    if (!fAttachingOrDetaching)
+        rc = 0;
+    if (    !rc
+        &&  (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL))
+    {
+        rc = kldrModPEDoCallDLL(pModPE, uOp, uHandle);
+        if (!fAttachingOrDetaching)
+            rc = 0;
+        if (rc)
+            kldrModPEDoCallTLS(pModPE, uOp, uHandle);
+    }
+
+    return rc;
+}
+
+
+/** @copydoc kLdrModSize */
+static KLDRADDR kldrModPESize(PKLDRMOD pMod)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+    return pModPE->Hdrs.OptionalHeader.SizeOfImage;
+}
+
+
+/** @copydoc kLdrModGetBits */
+static int kldrModPEGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODPE  pModPE = (PKLDRMODPE)pMod->pvData;
+    KU32        i;
+    int         rc;
+
+    /*
+     * Zero the entire buffer first to simplify things.
+     */
+    kHlpMemSet(pvBits, 0, pModPE->Hdrs.OptionalHeader.SizeOfImage);
+
+    /*
+     * Iterate the segments and read the data within them.
+     */
+    for (i = 0; i < pMod->cSegments; i++)
+    {
+        /* skip it? */
+        if (    pMod->aSegments[i].cbFile == -1
+            ||  pMod->aSegments[i].offFile == -1
+            ||  pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
+            ||  !pMod->aSegments[i].Alignment)
+            continue;
+        rc = kRdrRead(pMod->pRdr,
+                         (KU8 *)pvBits + (pMod->aSegments[i].LinkAddress - pModPE->Hdrs.OptionalHeader.ImageBase),
+                         pMod->aSegments[i].cbFile,
+                         pMod->aSegments[i].offFile);
+        if (rc)
+            return rc;
+    }
+
+    /*
+     * Perform relocations.
+     */
+    return kldrModPERelocateBits(pMod, pvBits, BaseAddress, pModPE->Hdrs.OptionalHeader.ImageBase, pfnGetImport, pvUser);
+
+}
+
+
+/** @copydoc kLdrModRelocateBits */
+static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
+                                 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
+{
+    PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
+    int rc;
+
+    /*
+     * Call workers to do the jobs.
+     */
+    rc = kldrModPEDoFixups(pModPE, pvBits, NewBaseAddress, OldBaseAddress);
+    if (!rc)
+        rc = kldrModPEDoImports(pModPE, pvBits, pfnGetImport, pvUser);
+
+    return rc;
+}
+
+
+/**
+ * The PE module interpreter method table.
+ */
+KLDRMODOPS g_kLdrModPEOps =
+{
+    "PE",
+    NULL,
+    kldrModPECreate,
+    kldrModPEDestroy,
+    kldrModPEQuerySymbol,
+    kldrModPEEnumSymbols,
+    kldrModPEGetImport,
+    kldrModPENumberOfImports,
+    NULL /* can execute one is optional */,
+    kldrModPEGetStackInfo,
+    kldrModPEQueryMainEntrypoint,
+    NULL, /** @todo resources */
+    NULL, /** @todo resources */
+    kldrModPEEnumDbgInfo,
+    kldrModPEHasDbgInfo,
+    kldrModPEMap,
+    kldrModPEUnmap,
+    kldrModPEAllocTLS,
+    kldrModPEFreeTLS,
+    kldrModPEReload,
+    kldrModPEFixupMapping,
+    kldrModPECallInit,
+    kldrModPECallTerm,
+    kldrModPECallThread,
+    kldrModPESize,
+    kldrModPEGetBits,
+    kldrModPERelocateBits,
+    NULL, /** @todo mostly done */
+    42 /* the end */
+};
Index: /trunk/kLdr/testcase/Makefile.kmk
===================================================================
--- /trunk/kLdr/testcase/Makefile.kmk	(revision 2)
+++ /trunk/kLdr/testcase/Makefile.kmk	(revision 2)
@@ -0,0 +1,301 @@
+# $Id$
+## @file
+# kBuild Makefile for the kLdr testcases.
+#
+
+#
+# Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kStuff 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+# generate rules.
+DEPTH ?= ../../..
+SUB_DEPTH = ../..
+include $(PATH_KBUILD)/subheader.kmk
+
+
+#
+# Templates for the testcases.
+#
+TEMPLATE_TST = Testcase template
+ifeq ($(BUILD_TARGET),win)
+ ifeq ($(BUILD_TARGET_ARCH),x86)
+  TEMPLATE_TST_TOOL = VCC70
+  TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD
+  TEMPLATE_TST_CXXFLAGS = -W3 -Zi -Zl -MD
+  TEMPLATE_TST_LIBS = \
+   	$(PATH_TOOL_VCC70_LIB)/oldnames.lib \
+   	$(PATH_TOOL_VCC70_LIB)/msvcrt.lib
+ else
+  TEMPLATE_TST_TOOL = VCC80AMD64
+  TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD
+  TEMPLATE_TST_CXXFLAGS = -W3 -Zi -Zl -MD
+  TEMPLATE_TST_LIBS = \
+   	$(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \
+   	$(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib
+ endif
+ TEMPLATE_TST_CFLAGS.release = -O2
+ TEMPLATE_TST_CXXFLAGS.release = -O2
+ TEMPLATE_TST_ASFLAGS = -f win
+ TEMPLATE_TST_DEFS = __WIN__
+ TEMPLATE_TST_SDKS.x86 = WIN32SDK
+ TEMPLATE_TST_SDKS.amd64 = WIN64SDK
+
+else
+ TEMPLATE_TST_CFLAGS = -Wall -pedantic -g
+ TEMPLATE_TST_CFLAGS.release = -O2
+ TEMPLATE_TST_LDFLAGS =
+ ifneq ($(filter os2,$(BUILD_TARGET)),)
+  TEMPLATE_TST_TOOL = GCC3OMF
+  TEMPLATE_TST_ASFLAGS = -f obj
+  TEMPLATE_TST_LIBS = os2 gcc end
+ else ifneq ($(filter darwin,$(BUILD_TARGET)),)
+  TEMPLATE_TST_TOOL = GCC4MACHO
+  TEMPLATE_TST_ASFLAGS = -f macho
+  TEMPLATE_TST_DEFS = __DARWIN__
+  TEMPLATE_TST_LIBS =
+ else
+  TEMPLATE_TST_TOOL = GCC3
+  TEMPLATE_TST_ASFLAGS = -f elf
+  TEMPLATE_TST_LIBS = gcc
+ endif
+endif
+TEMPLATE_TST_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include
+
+
+TEMPLATE_TSTPROG = Testcase program template
+TEMPLATE_TSTPROG_EXTENDS = TST
+
+
+TEMPLATE_TSTDLL = Testcase dll template
+TEMPLATE_TSTDLL_EXTENDS = TST
+
+
+TEMPLATE_TSTBARE = Bare bone testcase template
+ifeq ($(BUILD_TARGET),win)
+ ifeq ($(BUILD_TARGET_ARCH),x86)
+  TEMPLATE_TSTBARE_TOOL = VCC70
+ else
+  TEMPLATE_TSTBARE_TOOL = VCC80AMD64
+ endif
+ TEMPLATE_TSTBARE_CFLAGS = -W3 -Zi -Zl
+ TEMPLATE_TSTBARE_CFLAGS.release = -O2
+ TEMPLATE_TSTBARE_CXXFLAGS = -W3 -Zi -Zl
+ TEMPLATE_TSTBARE_CXXFLAGS.release = -O2
+ TEMPLATE_TSTBARE_ASFLAGS = -f win
+ TEMPLATE_TSTBARE_DEFS = __WIN__
+ TEMPLATE_TSTBARE_SDKS.x86 = WIN32SDK
+ TEMPLATE_TSTBARE_SDKS.amd64 = WIN64SDK
+
+else
+ TEMPLATE_TSTBARE_CFLAGS = -Wall -pedantic -g
+ TEMPLATE_TSTBARE_CFLAGS.release = -O2
+ TEMPLATE_TSTBARE_LDFLAGS = -nostdlib -lgcc
+ ifeq ($(filter-out os2,$(BUILD_TARGET)),)
+  TEMPLATE_TSTBARE_TOOL = GCC3OMF
+  TEMPLATE_TSTBARE_ASFLAGS = -f obj
+  TEMPLATE_TSTBARE_ASTOOL = NASM
+  TEMPLATE_TSTBARE_DEFS = main=main_wrapped
+  TEMPLATE_TSTBARE_LIBS = os2
+ else ifeq ($(filter-out darwin,$(BUILD_TARGET)),)
+  TEMPLATE_TSTBARE_TOOL = GCC4MACHO
+  TEMPLATE_TSTBARE_ASFLAGS = -f macho
+  TEMPLATE_TSTBARE_ASTOOL = NASM
+  TEMPLATE_TSTBARE_DEFS = __DARWIN__
+  TEMPLATE_TSTBARE_LIBS =
+  TEMPLATE_TSTBARE_CFLAGS += -static -fno-common
+  TEMPLATE_TSTBARE_LDFLAGS += -nostdlib -r
+ else
+  TEMPLATE_TSTBARE_TOOL = GCC3
+  TEMPLATE_TSTBARE_ASFLAGS = -f elf
+  TEMPLATE_TSTBARE_LIBS = gcc
+ endif
+endif
+TEMPLATE_TSTBARE_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include
+
+TEMPLATE_TSTBAREPROG = Bare bone testcase program template
+TEMPLATE_TSTBAREPROG_EXTENDS = TSTBARE
+ifneq ($(filter win win32 win64,$(BUILD_TARGET)),)
+TEMPLATE_TSTBAREPROG_LDFLAGS += -Entry:WindowsMain -FIXED:NO
+else
+TEMPLATE_TSTBAREPROG_LDFLAGS.nt += -FIXED:NO
+endif
+
+
+TEMPLATE_TSTBAREDLL = Bare bone testcase dll template
+TEMPLATE_TSTBAREDLL_EXTENDS = TSTBARE
+ifeq ($(BUILD_TARGET),win)
+ TEMPLATE_TSTBAREDLL_LDFLAGS += -Entry:DllMain
+else ifeq ($(BUILD_TARGET),darwin)
+# TEMPLATE_TSTBAREDLL_CFLAGS += -dynamiclib
+# TEMPLATE_TSTBAREDLL_LDFLAGS += -dynamiclib
+endif
+
+
+
+
+#
+# tst-0: four dlls, three of which depends on the 4th and no external dependencies.
+#        The purpose of this testcase is to debug the dynamic loader without
+#        messing with the native loader at all.
+#
+PROGRAMS += tst-0 tst-0-driver
+DLLS += tst-0-a tst-0-b tst-0-c tst-0-d
+
+tst-0-driver_TEMPLATE = TSTPROG
+tst-0-driver_SOURCES  = tst-0-driver.c
+
+tst-0-a_TEMPLATE = TSTBAREDLL
+tst-0-a_SOURCES  = tst-0-a.c tstDllMainStub.c
+tst-0-a_SOURCES.os2= tstDllMainStub-os2.asm
+
+tst-0-b_TEMPLATE = TSTBAREDLL
+tst-0-b_SOURCES  = tst-0-b.c tstDllMainStub.c
+tst-0-b_SOURCES.os2= tstDllMainStub-os2.asm
+
+tst-0-c_TEMPLATE = TSTBAREDLL
+tst-0-c_SOURCES  = tst-0-c.c tstDllMainStub.c
+tst-0-c_SOURCES.os2= tstDllMainStub-os2.asm
+
+tst-0-d_TEMPLATE = TSTBAREDLL
+tst-0-d_SOURCES  = tst-0-d.c tstDllMainStub.c
+tst-0-d_SOURCES.os2= tstDllMainStub-os2.asm
+
+tst-0_TEMPLATE   = TSTBAREPROG
+tst-0_SOURCES    = tst-0.c tstExeMainStub.c
+tst-0_SOURCES.os2= tstExeMainStub-os2.asm
+
+ifeq ($(BUILD_TARGET),win)
+tst-0-driver_LIBS= $(PATH_LIB)/kLdr.lib
+tst-0-a_LIBS     = $(PATH_TARGET)/tst-0-d/tst-0-d.lib
+tst-0-b_LIBS     = $(PATH_TARGET)/tst-0-d/tst-0-d.lib
+tst-0-c_LIBS     = $(PATH_TARGET)/tst-0-d/tst-0-d.lib
+tst-0_LIBS       = $(TARGET_tst-0-a:.dll=.lib) $(TARGET_tst-0-b:.dll=.lib) $(TARGET_tst-0-c:.dll=.lib)
+else
+tst-0-driver_LIBS= $(PATH_DLL)/kLdr$(SUFF_DLL)
+tst-0-a_LIBS     = $(subst -a,-d,$(TARGET_tst-0-a))
+tst-0-b_LIBS     = $(subst -b,-d,$(TARGET_tst-0-b))
+tst-0-c_LIBS     = $(subst -c,-d,$(TARGET_tst-0-c))
+tst-0_LIBS       = $(TARGET_tst-0-a) $(TARGET_tst-0-b) $(TARGET_tst-0-c)
+endif
+
+
+#
+# tst-1: four dlls, three of which depends on the 4th and the testcase depends on those three again.
+#
+PROGRAMS += tst-1
+DLLS += tst-1-a tst-1-b tst-1-c tst-1-d
+
+tst-1-a_TEMPLATE = TSTDLL
+tst-1-a_SOURCES  = tst-1-a.c tstDllMain.c
+
+tst-1-b_TEMPLATE = TSTDLL
+tst-1-b_SOURCES  = tst-1-b.c tstDllMain.c
+
+tst-1-c_TEMPLATE = TSTDLL
+tst-1-c_SOURCES  = tst-1-c.c tstDllMain.c
+
+tst-1-d_TEMPLATE = TSTDLL
+tst-1-d_SOURCES  = tst-1-d.c tstDllMain.c
+
+tst-1_TEMPLATE   = TSTPROG
+tst-1_SOURCES    = tst-1.c
+
+ifeq ($(BUILD_TARGET),win)
+tst-1-a_LIBS     = $(PATH_TARGET)/tst-1-d/tst-1-d.lib
+tst-1-b_LIBS     = $(PATH_TARGET)/tst-1-d/tst-1-d.lib
+tst-1-c_LIBS     = $(PATH_TARGET)/tst-1-d/tst-1-d.lib
+tst-1_LIBS       = $(TARGET_tst-1-a:.dll=.lib) $(TARGET_tst-1-b:.dll=.lib) $(TARGET_tst-1-c:.dll=.lib)
+else
+tst-1-a_LIBS     = $(subst -a,-d,$(TARGET_tst-1-a))
+tst-1-b_LIBS     = $(subst -b,-d,$(TARGET_tst-1-b))
+tst-1-c_LIBS     = $(subst -c,-d,$(TARGET_tst-1-c))
+tst-1_LIBS       = $(TARGET_tst-1-a) $(TARGET_tst-1-b) $(TARGET_tst-1-c)
+endif
+
+
+#
+# tst-2: four dlls, three of which depends on the 1st, and the testcase depends on those all of them.
+#
+PROGRAMS += tst-2
+DLLS += tst-2-a tst-2-b tst-2-c tst-2-d
+
+tst-2-a_TEMPLATE = TSTDLL
+tst-2-a_SOURCES  = tst-2-a.c tstDllMain.c
+
+tst-2-b_TEMPLATE = TSTDLL
+tst-2-b_SOURCES  = tst-2-b.c tstDllMain.c
+
+tst-2-c_TEMPLATE = TSTDLL
+tst-2-c_SOURCES  = tst-2-c.c tstDllMain.c
+
+tst-2-d_TEMPLATE = TSTDLL
+tst-2-d_SOURCES  = tst-2-d.c tstDllMain.c
+
+tst-2_TEMPLATE   = TSTPROG
+tst-2_SOURCES    = tst-2.c
+
+ifeq ($(BUILD_TARGET),win)
+tst-2-b_LIBS     = $(PATH_TARGET)/tst-2-a/tst-2-a.lib
+tst-2-c_LIBS     = $(PATH_TARGET)/tst-2-a/tst-2-a.lib
+tst-2-d_LIBS     = $(PATH_TARGET)/tst-2-a/tst-2-a.lib
+tst-2_LIBS       = $(TARGET_tst-2-b:.dll=.lib) $(TARGET_tst-2-c:.dll=.lib) $(TARGET_tst-2-d:.dll=.lib) $(TARGET_tst-2-a:.dll=.lib)
+else
+tst-2-b_LIBS     = $(subst -b,-a,$(TARGET_tst-2-b))
+tst-2-c_LIBS     = $(subst -c,-a,$(TARGET_tst-2-c))
+tst-2-d_LIBS     = $(subst -d,-a,$(TARGET_tst-2-d))
+tst-2_LIBS       = $(TARGET_tst-2-a) $(TARGET_tst-2-b) $(TARGET_tst-2-c) $(TARGET_tst-2-d)
+endif
+
+
+#
+# tst-3: Single module.
+#
+PROGRAMS += tst-3-driver
+ifeq ($(BUILD_TARGET),darwin)
+SYSMODS += tst-3
+else
+DLLS += tst-3
+LIBRARIES.win += tst-3-imp
+LIBRARIES.os2 += tst-3-imp
+endif
+
+tst-3_TEMPLATE = TSTBAREDLL
+tst-3_SOURCES  = tst-3.c tst-3-ext.c tstDllMainStub.c
+tst-3_SOURCES.os2= tstDllMainStub-os2.asm
+tst-3_LIBS.os2 = $(TARGET_tst-3-imp)
+tst-3_LIBS.win = $(TARGET_tst-3-imp)
+
+tst-3-imp_TEMPLATE = TSTBAREDLL
+tst-3-imp_SOURCES.win = tst-3-imp-win.def
+tst-3-imp_SOURCES.os2 = tst-3-imp-os2.def
+
+tst-3-driver_TEMPLATE = TSTPROG
+tst-3-driver_SOURCES  = tst-3-driver.c
+
+ifeq ($(BUILD_TARGET),win)
+tst-3-driver_LIBS = $(PATH_LIB)/kLdr.lib
+else
+tst-3-driver_LIBS = $(PATH_DLL)/kLdr$(SUFF_DLL)
+endif
+
+
+# generate rules.
+include $(PATH_KBUILD)/subfooter.kmk
+
Index: /trunk/kLdr/testcase/tst-0-a.c
===================================================================
--- /trunk/kLdr/testcase/tst-0-a.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-0-a.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "a";
+
+MY_IMPORT(int) FuncD(void);
+
+MY_EXPORT(int) FuncA(void)
+{
+    return FuncD() | (g_pszName[0] == 'a' ? 0x42 : 0x0001);
+}
+
Index: /trunk/kLdr/testcase/tst-0-b.c
===================================================================
--- /trunk/kLdr/testcase/tst-0-b.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-0-b.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "b";
+
+MY_IMPORT(int) FuncD(void);
+
+MY_EXPORT(int) FuncB(void)
+{
+    return FuncD() | (g_pszName[0] == 'b' ? 0x4200 : 0x0010);
+}
+
Index: /trunk/kLdr/testcase/tst-0-c.c
===================================================================
--- /trunk/kLdr/testcase/tst-0-c.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-0-c.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "c";
+
+MY_IMPORT(int) FuncD(void);
+
+MY_EXPORT(int) FuncC(void)
+{
+    return FuncD() | (g_pszName[0] == 'c' ? 0x420000 : 0x0100);
+}
+
Index: /trunk/kLdr/testcase/tst-0-d.c
===================================================================
--- /trunk/kLdr/testcase/tst-0-d.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-0-d.c	(revision 2)
@@ -0,0 +1,8 @@
+#include "tst.h"
+const char *g_pszName = "d";
+
+MY_EXPORT(int) FuncD(void)
+{
+    return g_pszName[0] == 'd' ? 0x42000000 : 0x1000;
+}
+
Index: /trunk/kLdr/testcase/tst-0-driver.c
===================================================================
--- /trunk/kLdr/testcase/tst-0-driver.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-0-driver.c	(revision 2)
@@ -0,0 +1,498 @@
+/* $Id$ */
+/** @file
+ * kLdr - Dynamic Loader testcase no. 0, Driver.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "tst.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** Select the appropriate KLDRSYMKIND bit define. */
+#define MY_KLDRSYMKIND_BITS     ( sizeof(void *) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT )
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The numbers of errors. */
+static int g_cErrors = 0;
+
+
+
+/**
+ * Report failure.
+ */
+static int Failure(const char *pszFormat, ...)
+{
+    va_list va;
+
+    g_cErrors++;
+
+    printf("tst-0-driver: ");
+    va_start(va, pszFormat);
+    vprintf(pszFormat, va);
+    va_end(va);
+    printf("\n");
+    return 1;
+}
+
+
+int main(int argc, char **argv)
+{
+    const char *pszErrInit = "Error, szErr wasn't zapped";
+    char szErr[512];
+    char szBuf[512];
+    char *psz;
+    KSIZE cch;
+    HKLDRMOD hMod;
+    int rc;
+
+    /*
+     * The first thing to do is a simple load / unload test
+     * using the tst-0-a library (it'll drag in tst-0-d).
+     */
+    printf("tst-0-driver: Basic API test using 'tst-0-a'...\n");
+    hMod = (HKLDRMOD)0xffffeeee;
+    strcpy(szErr, pszErrInit);
+    rc = kLdrDyldLoad("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST,
+                      KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, &hMod, szErr, sizeof(szErr));
+    if (rc)
+        Failure("kLdrDyldLoad(\"tst-0\",...) failed, rc=%d (%#x). szErr='%s'.\n", rc, rc, szErr);
+    if (!strcmp(szErr, pszErrInit))
+        Failure("szErr wasn't set.\n");
+    if (hMod == (HKLDRMOD)0xffffeeee)
+        Failure("hMod wasn't set.\n");
+    if (hMod == NIL_HKLDRMOD && !rc)
+        Failure("rc=0 but hMod=NIL_HKLDRMOD\n");
+    if (!rc)
+    {
+        HKLDRMOD hMod2;
+        HKLDRMOD hMod3;
+        printf("tst-0-driver: hMod=%p ('tst-0-a')\n", (void *)hMod);
+
+        /*
+         * Simple test of kLdrDyldFindByName.
+         */
+        hMod2 = (HKLDRMOD)0xffffeeee;
+        rc = kLdrDyldFindByName("tst-0", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2);
+        if (!rc)
+            Failure("kLdrDyldFindByName(\"tst-0\",,,) didn't fail!\n");
+        if (rc && hMod2 != NIL_HKLDRMOD)
+            Failure("hMod2 wasn't set correctly on kLdrDyldFindByName failure!\n");
+
+        hMod2 = (HKLDRMOD)0xffffeeee;
+        rc = kLdrDyldFindByName("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2);
+        if (rc)
+            Failure("kLdrDyldFindByName(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc);
+        if (!rc && hMod2 != hMod)
+            Failure("kLdrDyldFindByName(\"tst-0-a\",,,) returned the wrong module handle: %p instead of %p\n",
+                    (void *)hMod2, (void *)hMod);
+
+        hMod2 = (HKLDRMOD)0xffffeeee;
+        rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2);
+        if (!rc)
+            printf("tst-0-driver: hMod2=%p ('tst-0-d')\n", (void *)hMod2);
+        else
+            Failure("kLdrDyldFindByName(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc);
+
+        /*
+         * Get the name and filename for each of the two modules.
+         */
+        rc = kLdrDyldGetName(hMod2, szBuf, sizeof(szBuf));
+        if (!rc)
+        {
+            printf("tst-0-driver: name: '%s' ('tst-0-d')\n", szBuf);
+            psz = strstr(szBuf, "-0-");
+            if (    !psz
+                ||  strnicmp(psz, "-0-d", sizeof("-0-d") - 1))
+                Failure("kLdrDyldGetName(\"tst-0-d\",,,) -> '%s': pattern '-0-d' not found\n", szBuf);
+
+            /* overflow test. */
+            cch = strlen(szBuf);
+            szBuf[cch + 1] = szBuf[cch] = szBuf[cch - 1] = 'x';
+            szBuf[cch + 2] = '\0';
+            rc = kLdrDyldGetName(hMod2, szBuf, cch);
+            if (rc == KERR_BUFFER_OVERFLOW)
+            {
+                if (!szBuf[0])
+                    Failure("kLdrDyldGetName didn't return partial result on overflow\n");
+                else if (szBuf[cch - 1])
+                    Failure("kLdrDyldGetName didn't terminate partial result correctly overflow: '%s'\n", szBuf);
+                else if (szBuf[cch] != 'x')
+                    Failure("kLdrDyldGetName exceeded the buffer limit on partial overflow: '%s'\n", szBuf);
+            }
+            else
+                Failure("kLdrDyldGetName(\"tst-0-d\",,,) -> rc=%d (%#x) instead of KERR_BUFFER_OVERFLOW\n", rc, rc);
+
+            /* check that we can query the module by the returned name. */
+            rc = kLdrDyldGetName(hMod2, szBuf, sizeof(szBuf));
+            if (!rc)
+            {
+                hMod3 = (HKLDRMOD)0xffffeeee;
+                rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3);
+                if (rc || hMod3 != hMod2)
+                    Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod2=%p\n",
+                            szBuf, rc, rc, (void *)hMod3, (void *)hMod2);
+            }
+            else
+                Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed (b), rc=%d (%#x)\n", rc, rc);
+        }
+        else
+            Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc);
+
+        rc = kLdrDyldGetFilename(hMod2, szBuf, sizeof(szBuf));
+        if (!rc)
+        {
+            printf("tst-0-driver: filename: '%s' ('tst-0-d')\n", szBuf);
+
+            /* overflow test. */
+            cch = strlen(szBuf);
+            szBuf[cch + 1] = szBuf[cch] = szBuf[cch - 1] = 'x';
+            szBuf[cch + 2] = '\0';
+            rc = kLdrDyldGetFilename(hMod2, szBuf, cch);
+            if (rc == KERR_BUFFER_OVERFLOW)
+            {
+                if (!szBuf[0])
+                    Failure("kLdrDyldGetFilename didn't return partial result on overflow\n");
+                else if (szBuf[cch - 1])
+                    Failure("kLdrDyldGetFilename didn't terminate partial result correctly overflow: '%s'\n", szBuf);
+                else if (szBuf[cch] != 'x')
+                    Failure("kLdrDyldGetFilename exceeded the buffer limit on partial overflow: '%s'\n", szBuf);
+            }
+            else
+                Failure("kLdrDyldGetFilename(\"tst-0-d\",,,) -> rc=%d (%#x) instead of KERR_BUFFER_OVERFLOW\n", rc, rc);
+
+            /* check that we can query the module by the returned filename. */
+            rc = kLdrDyldGetFilename(hMod2, szBuf, sizeof(szBuf));
+            if (!rc)
+            {
+                hMod3 = (HKLDRMOD)0xffffeeee;
+                rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3);
+                if (rc || hMod3 != hMod2)
+                    Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod2=%p\n",
+                            szBuf, rc, rc, (void *)hMod3, (void *)hMod2);
+            }
+            else
+                Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed (b), rc=%d (%#x)\n", rc, rc);
+        }
+        else
+            Failure("kLdrDyldGetFilename(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc);
+
+        /* the other module */
+        rc = kLdrDyldGetName(hMod, szBuf, sizeof(szBuf));
+        if (!rc)
+        {
+            printf("tst-0-driver: name: '%s' ('tst-0-a')\n", szBuf);
+            psz = strstr(szBuf, "-0-");
+            if (    !psz
+                ||  strnicmp(psz, "-0-a", sizeof("-0-a") - 1))
+                Failure("kLdrDyldGetName(\"tst-0-a\",,,) -> '%s': pattern '-0-a' not found\n", szBuf);
+
+            /* check that we can query the module by the returned name. */
+            hMod3 = (HKLDRMOD)0xffffeeee;
+            rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3);
+            if (rc || hMod3 != hMod)
+                Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod=%p\n",
+                        szBuf, rc, rc, (void *)hMod3, (void *)hMod);
+        }
+        else
+            Failure("kLdrDyldGetName(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc);
+
+        rc = kLdrDyldGetFilename(hMod, szBuf, sizeof(szBuf));
+        if (!rc)
+        {
+            printf("tst-0-driver: filename: '%s' ('tst-0-a')\n", szBuf);
+
+            /* check that we can query the module by the returned filename. */
+            hMod3 = (HKLDRMOD)0xffffeeee;
+            rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3);
+            if (rc || hMod3 != hMod)
+                Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod=%p\n",
+                        szBuf, rc, rc, (void *)hMod3, (void *)hMod);
+        }
+        else
+            Failure("kLdrDyldGetFilename(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc);
+
+
+        /*
+         * Resolve the symbol exported by each of the two modules and call them.
+         */
+        if (!g_cErrors)
+        {
+            KUPTR uValue;
+            KU32  fKind;
+
+            fKind = 0xffeeffee;
+            uValue = ~(KUPTR)42;
+            rc = kLdrDyldQuerySymbol(hMod, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncA"), NULL, &uValue, &fKind);
+            if (!rc)
+            {
+                if (uValue == ~(KUPTR)42)
+                    Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",): uValue wasn't set.\n");
+                if (fKind == 0xffeeffee)
+                    Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",): fKind wasn't set.\n");
+                if (    (fKind & KLDRSYMKIND_BIT_MASK) != KLDRSYMKIND_NO_BIT
+                    &&  (fKind & KLDRSYMKIND_BIT_MASK) != MY_KLDRSYMKIND_BITS)
+                    Failure("fKind=%#x indicates a different code 'bit' mode than we running at.\n", fKind);
+                if (    (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_NO_TYPE
+                    &&  (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_CODE)
+                    Failure("fKind=%#x indicates that \"FuncA\" isn't code.\n", fKind);
+                if (fKind & KLDRSYMKIND_FORWARDER)
+                    Failure("fKind=%#x indicates that \"FuncA\" is a forwarder. it isn't.\n", fKind);
+
+                /* call it. */
+                if (!g_cErrors)
+                {
+                    int (*pfnFuncA)(void) = (int (*)(void))uValue;
+                    rc = pfnFuncA();
+                    if (rc != 0x42000042)
+                        Failure("FuncA returned %#x expected 0x42000042\n", rc);
+                }
+
+                /*
+                 * Test kLdrDyldFindByAddress now that we've got an address.
+                 */
+                hMod3 = (HKLDRMOD)0xeeeeffff;
+                rc = kLdrDyldFindByAddress(uValue, &hMod3, NULL, NULL);
+                if (!rc)
+                {
+                    KUPTR offSegment;
+                    KU32 iSegment;
+
+                    if (hMod3 != hMod)
+                        Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) return incorrect hMod3=%p instead of %p.\n",
+                                uValue, hMod3, hMod);
+
+                    hMod3 = (HKLDRMOD)0xeeeeffff;
+                    iSegment = 0x42424242;
+                    rc = kLdrDyldFindByAddress(uValue, &hMod3, &iSegment, &offSegment);
+                    if (!rc)
+                    {
+                        if (hMod3 != hMod)
+                            Failure("Bad hMod3 on 2nd kLdrDyldFindByAddress call.\n");
+                        if (iSegment > 0x1000) /* safe guess */
+                            Failure("Bad iSegment=%#x\n", iSegment);
+                        if (offSegment > 0x100000) /* guesswork */
+                            Failure("Bad offSegment=%p\n", (void *)offSegment);
+                    }
+                    else
+                        Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) failed (b), rc=%d (%#x)\n",
+                                uValue, rc, rc);
+
+                    /* negative test */
+                    hMod3 = (HKLDRMOD)0xeeeeffff;
+                    iSegment = 0x42424242;
+                    offSegment = 0x87654321;
+                    rc = kLdrDyldFindByAddress(~(KUPTR)16, &hMod3, &iSegment, &offSegment);
+                    if (!rc)
+                        Failure("negative kLdrDyldFindByAddress test returned successfully!\n");
+                    if (iSegment != ~(KU32)0)
+                        Failure("negative kLdrDyldFindByAddress: bad iSegment=%#x\n", iSegment);
+                    if (offSegment != ~(KUPTR)0)
+                        Failure("negative kLdrDyldFindByAddress: bad offSegment=%p\n", (void *)offSegment);
+                    if (hMod3 != NIL_HKLDRMOD)
+                        Failure("negative kLdrDyldFindByAddress: bad hMod3=%p\n", (void *)hMod3);
+                }
+                else
+                    Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) failed, rc=%d (%#x)\n",
+                            uValue, rc, rc);
+            }
+            else
+                Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",) failed, rc=%d (%#x)\n", rc, rc);
+
+            fKind = 0xffeeffee;
+            uValue = ~(KUPTR)42;
+            rc = kLdrDyldQuerySymbol(hMod2, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncD"), NULL, &uValue, &fKind);
+            if (!rc)
+            {
+                if (uValue == ~(KUPTR)42)
+                    Failure("kLdrDyldQuerySymbol(\"tst-0-d\",,\"FuncD\",): uValue wasn't set.\n");
+                if (fKind == 0xffeeffee)
+                    Failure("kLdrDyldQuerySymbol(\"tst-0-d\",,\"FuncD\",): fKind wasn't set.\n");
+                if (    (fKind & KLDRSYMKIND_BIT_MASK) != KLDRSYMKIND_NO_BIT
+                    &&  (fKind & KLDRSYMKIND_BIT_MASK) != MY_KLDRSYMKIND_BITS)
+                    Failure("fKind=%#x indicates a different code 'bit' mode than we running at.\n", fKind);
+                if (    (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_NO_TYPE
+                    &&  (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_CODE)
+                    Failure("fKind=%#x indicates that \"FuncD\" isn't code.\n", fKind);
+                if (fKind & KLDRSYMKIND_FORWARDER)
+                    Failure("fKind=%#x indicates that \"FuncD\" is a forwarder. it isn't.\n", fKind);
+
+                /* call it. */
+                if (!g_cErrors)
+                {
+                    int (*pfnFuncD)(void) = (int (*)(void))uValue;
+                    rc = pfnFuncD();
+                    if (rc != 0x42000000)
+                        Failure("FuncD returned %#x expected 0x42000000\n", rc);
+                }
+
+                /* use the address to get the module handle. */
+                hMod3 = (HKLDRMOD)0xeeeeffff;
+                rc = kLdrDyldFindByAddress(uValue, &hMod3, NULL, NULL);
+                if (!rc)
+                {
+                    if (hMod3 != hMod2)
+                        Failure("kLdrDyldFindByAddress(%#p/*FuncD*/,,,) return incorrect hMod3=%p instead of %p.\n",
+                                uValue, hMod3, hMod2);
+                }
+                else
+                    Failure("kLdrDyldFindByAddress(%#p/*FuncD*/,,,) failed, rc=%d (%#x)\n",
+                            uValue, rc, rc);
+            }
+            else
+                Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",) failed, rc=%d (%#x)\n", rc, rc);
+
+        }
+
+        /*
+         * Finally unload it.
+         */
+        rc = kLdrDyldUnload(hMod);
+        if (rc)
+            Failure("kLdrDyldUnload() failed. rc=%d (%#x)\n", rc, rc);
+        if (!rc)
+        {
+            rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                Failure("kLdrDyldFindByName(\"tst-0-d\",,,) return rc=%d (%#x), expected KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc);
+
+            rc = kLdrDyldFindByName("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                Failure("kLdrDyldFindByName(\"tst-0-a\",,,) return rc=%d (%#x), expected KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc);
+        }
+    }
+
+    /*
+     * Now do what tst-0 would do; load the three dlls, resolve and call their functions.
+     */
+    if (!g_cErrors)
+    {
+        HKLDRMOD hModA;
+        int (*pfnFuncA)(void);
+        HKLDRMOD hModB;
+        int (*pfnFuncB)(void);
+        HKLDRMOD hModC;
+        int (*pfnFuncC)(void);
+        KUPTR uValue;
+
+        rc = kLdrDyldLoad("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModA, NULL, 0);
+        if (rc)
+            Failure("kLdrDyldLoad(\"tst-0-a\",,,,) -> %d (%#x)\n", rc, rc);
+        if (!rc)
+        {
+            rc = kLdrDyldLoad("tst-0-b", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModB, szErr, sizeof(szErr));
+            if (rc)
+                Failure("kLdrDyldLoad(\"tst-0-b\",,,,) -> %d (%#x) szErr='%s'\n", rc, rc, szErr);
+        }
+        if (!rc)
+        {
+            rc = kLdrDyldLoad("tst-0-c", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModC, szErr, sizeof(szErr));
+            if (rc)
+                Failure("kLdrDyldLoad(\"tst-0-c\",,,,) -> %d (%#x) szErr='%s'\n", rc, rc, szErr);
+        }
+        if (!rc)
+        {
+            rc = kLdrDyldQuerySymbol(hModA, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncA"), NULL, &uValue, NULL);
+            if (!rc)
+                pfnFuncA = (int (*)(void))uValue;
+            else
+                Failure("kLdrDyldQuerySymbol(,,\"FuncA\",,) -> %d (%#x)\n", rc, rc);
+        }
+        if (!rc)
+        {
+            rc = kLdrDyldQuerySymbol(hModB, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncB"), NULL, &uValue, NULL);
+            if (!rc)
+                pfnFuncB = (int (*)(void))uValue;
+            else
+                Failure("kLdrDyldQuerySymbol(,,\"FuncB\",,) -> %d (%#x)\n", rc, rc);
+        }
+        if (!rc)
+        {
+            rc = kLdrDyldQuerySymbol(hModC, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncC"), NULL, &uValue, NULL);
+            if (!rc)
+                pfnFuncC = (int (*)(void))uValue;
+            else
+                Failure("kLdrDyldQuerySymbol(,,\"FuncA\",,) -> %d (%#x)\n", rc, rc);
+        }
+        if (!rc)
+        {
+            int u = pfnFuncA() | pfnFuncB() | pfnFuncC();
+            if (u == 0x42424242)
+                printf("tst-0-driver: FuncA/B/C => %#x (correct)\n", u);
+            else
+                Failure("FuncA/B/C => %#x\n", u);
+
+            rc = kLdrDyldUnload(hModA);
+            if (rc)
+                Failure("Unload A failed, rc=%d (%#x)\n", rc, rc);
+            u = pfnFuncB() | pfnFuncC();
+            if (u != 0x42424200)
+                Failure("FuncB/C returns %#x instead of 0x42424200 after unloading A\n", u);
+
+            rc = kLdrDyldUnload(hModB);
+            if (rc)
+                Failure("Unload B failed, rc=%d (%#x)\n", rc, rc);
+            u = pfnFuncC();
+            if (u != 0x42420000)
+                Failure("FuncC returns %#x instead of 0x42420000 after unloading A\n", u);
+
+            rc = kLdrDyldUnload(hModC);
+            if (rc)
+                Failure("Unload C failed, rc=%d (%#x)\n", rc, rc);
+
+            rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod);
+            if (rc != KLDR_ERR_MODULE_NOT_FOUND)
+                Failure("Query for \"tst-0-d\" after unloading A,B and C returns rc=%d (%#x) instead of KLDR_ERR_MODULE_NOT_FOUND\n",
+                        rc, rc);
+        }
+    }
+
+    /*
+     * Now invoke the executable stub which launches the tst-0 program.
+     */
+    if (!g_cErrors)
+    {
+        /// @todo
+    }
+
+    /*
+     * Summary
+     */
+    if (!g_cErrors)
+        printf("tst-0-driver: SUCCESS\n");
+    else
+        printf("tst-0-driver: FAILURE - %d errors\n", g_cErrors);
+    return !!g_cErrors;
+}
+
Index: /trunk/kLdr/testcase/tst-0.c
===================================================================
--- /trunk/kLdr/testcase/tst-0.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-0.c	(revision 2)
@@ -0,0 +1,13 @@
+#include "tst.h"
+
+MY_IMPORT(int) FuncA(void);
+MY_IMPORT(int) FuncB(void);
+MY_IMPORT(int) FuncC(void);
+
+int main()
+{
+    unsigned u;
+    u = FuncA() | FuncB() | FuncC();
+    return u == 0x42424242 ? 0 : 1;
+}
+
Index: /trunk/kLdr/testcase/tst-1-a.c
===================================================================
--- /trunk/kLdr/testcase/tst-1-a.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-1-a.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "a";
+
+MY_IMPORT(int) FuncD(void);
+
+MY_EXPORT(int) FuncA(void)
+{
+    return FuncD();
+}
+
Index: /trunk/kLdr/testcase/tst-1-b.c
===================================================================
--- /trunk/kLdr/testcase/tst-1-b.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-1-b.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "b";
+
+MY_IMPORT(int) FuncD(void);
+
+MY_EXPORT(int) FuncB(void)
+{
+    return FuncD();
+}
+
Index: /trunk/kLdr/testcase/tst-1-c.c
===================================================================
--- /trunk/kLdr/testcase/tst-1-c.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-1-c.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "c";
+
+MY_IMPORT(int) FuncD(void);
+
+MY_EXPORT(int) FuncC(void)
+{
+    return FuncD();
+}
+
Index: /trunk/kLdr/testcase/tst-1-d.c
===================================================================
--- /trunk/kLdr/testcase/tst-1-d.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-1-d.c	(revision 2)
@@ -0,0 +1,8 @@
+#include "tst.h"
+const char *g_pszName = "d";
+
+MY_EXPORT(int) FuncD(void)
+{
+    return 0;
+}
+
Index: /trunk/kLdr/testcase/tst-1.c
===================================================================
--- /trunk/kLdr/testcase/tst-1.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-1.c	(revision 2)
@@ -0,0 +1,15 @@
+#include "tst.h"
+#include <stdio.h>
+
+MY_IMPORT(int) FuncA(void);
+MY_IMPORT(int) FuncB(void);
+MY_IMPORT(int) FuncC(void);
+
+int main()
+{
+    printf("graph:\n"
+           "  tst-1 -> a -> d\n"
+           "           b -> d\n"
+           "           c -> d\n");
+    return FuncA() + FuncB() + FuncC();
+}
Index: /trunk/kLdr/testcase/tst-2-a.c
===================================================================
--- /trunk/kLdr/testcase/tst-2-a.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-2-a.c	(revision 2)
@@ -0,0 +1,8 @@
+#include "tst.h"
+const char *g_pszName = "a";
+
+MY_EXPORT(int) FuncA(void)
+{
+    return 0;
+}
+
Index: /trunk/kLdr/testcase/tst-2-b.c
===================================================================
--- /trunk/kLdr/testcase/tst-2-b.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-2-b.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "b";
+
+MY_IMPORT(int) FuncA(void);
+
+MY_EXPORT(int) FuncB(void)
+{
+    return FuncA();
+}
+
Index: /trunk/kLdr/testcase/tst-2-c.c
===================================================================
--- /trunk/kLdr/testcase/tst-2-c.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-2-c.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "c";
+
+MY_IMPORT(int) FuncA(void);
+
+MY_EXPORT(int) FuncC(void)
+{
+    return FuncA();
+}
+
Index: /trunk/kLdr/testcase/tst-2-d.c
===================================================================
--- /trunk/kLdr/testcase/tst-2-d.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-2-d.c	(revision 2)
@@ -0,0 +1,10 @@
+#include "tst.h"
+const char *g_pszName = "d";
+
+MY_IMPORT(int) FuncA(void);
+
+MY_EXPORT(int) FuncD(void)
+{
+    return FuncA();
+}
+
Index: /trunk/kLdr/testcase/tst-2.c
===================================================================
--- /trunk/kLdr/testcase/tst-2.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-2.c	(revision 2)
@@ -0,0 +1,16 @@
+#include "tst.h"
+
+MY_IMPORT(int) FuncA(void);
+MY_IMPORT(int) FuncB(void);
+MY_IMPORT(int) FuncC(void);
+MY_IMPORT(int) FuncD(void);
+
+int main()
+{
+    printf("graph:\n"
+           "  tst-2 -> b -> a\n"
+           "           c -> a\n"
+           "           d -> a\n"
+           "           a\n");
+    return FuncA() + FuncB() + FuncC() + FuncD();
+}
Index: /trunk/kLdr/testcase/tst-3-driver.c
===================================================================
--- /trunk/kLdr/testcase/tst-3-driver.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-3-driver.c	(revision 2)
@@ -0,0 +1,212 @@
+/* $Id$ */
+/** @file
+ * kLdr - Dynamic Loader testcase no. 3, Driver.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "tst.h"
+#include <k/kErr.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _MSC_VER
+# include <malloc.h>
+#endif
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** Select the appropriate KLDRSYMKIND bit define. */
+#define MY_KLDRSYMKIND_BITS     ( sizeof(void *) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT )
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The numbers of errors. */
+static int g_cErrors = 0;
+
+
+/**
+ * Report failure.
+ */
+static int Failure(const char *pszFormat, ...)
+{
+    va_list va;
+
+    g_cErrors++;
+
+    printf("tst-3-driver: ");
+    va_start(va, pszFormat);
+    vprintf(pszFormat, va);
+    va_end(va);
+    printf("\n");
+    return 1;
+}
+
+
+/**
+ * External symbol used by the testcase module.
+ */
+static int Tst3Ext(int iFortyTwo)
+{
+    if (iFortyTwo != 42)
+        return 256;
+    return 42;
+}
+
+
+/**
+ * Callback for resolving the Tst3Ext import.
+ */
+static int GetImport(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
+                     const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser)
+{
+    if (*pfKind != KLDRSYMKIND_REQ_FLAT)
+        return -1;
+
+    if (    !strncmp(pchSymbol, "Tst3Ext", strlen("Tst3Ext"))
+        ||  !strncmp(pchSymbol, "_Tst3Ext", strlen("_Tst3Ext")))
+    {
+        *puValue = (KUPTR)&Tst3Ext;
+        *pfKind = KLDRSYMKIND_CODE | (sizeof(pfKind) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT);
+        return 0;
+    }
+
+    return -2;
+}
+
+
+/**
+ * Performs the tests on one module.
+ * @returns non sense.
+ */
+int TestModule(const char *pszFile)
+{
+    PKLDRMOD pMod;
+    KLDRSIZE cbImage;
+    void *pvBits;
+    int rc;
+
+    printf("tst-3-driver: testing '%s'...\n", pszFile);
+
+    /* open it. */
+    rc = kLdrModOpen(pszFile, &pMod);
+    if (rc)
+        return Failure("kLdrModOpen(%s,) -> %#d (%s)\n", pszFile, rc, kErrName(rc));
+
+    /* get bits. */
+    cbImage = kLdrModSize(pMod);
+    pvBits = malloc((KSIZE)cbImage + 0xfff);
+    if (pvBits)
+    {
+        void *pvBits2 = (void *)( ((KUPTR)pvBits + 0xfff) & ~(KUPTR)0xfff );
+
+        KLDRADDR BaseAddress = (KUPTR)pvBits2;
+        rc = kLdrModGetBits(pMod, pvBits2, BaseAddress, GetImport, NULL);
+        if (!rc)
+        {
+            KLDRADDR EntryPoint;
+
+            /* call into it */
+            rc = kLdrModQuerySymbol(pMod, pvBits2, BaseAddress, NIL_KLDRMOD_SYM_ORDINAL, "_Tst3", strlen("_Tst3"), NULL, NULL, NULL,
+                                    &EntryPoint, NULL);
+            if (rc == KLDR_ERR_SYMBOL_NOT_FOUND)
+                rc = kLdrModQuerySymbol(pMod, pvBits2, BaseAddress, NIL_KLDRMOD_SYM_ORDINAL, "Tst3", strlen("Tst3"), NULL, NULL, NULL,
+                                        &EntryPoint, NULL);
+            if (!rc)
+            {
+                int (*pfnEntryPoint)(int) = (int (*)(int)) ((KUPTR)EntryPoint);
+                rc = pfnEntryPoint(42);
+                if (rc == 42)
+                {
+                    /* relocate twice and try again. */
+                    rc = kLdrModRelocateBits(pMod, pvBits2, BaseAddress + 0x22000, BaseAddress, GetImport, NULL);
+                    if (!rc)
+                    {
+                        rc = kLdrModRelocateBits(pMod, pvBits2, BaseAddress, BaseAddress + 0x22000, GetImport, NULL);
+                        if (!rc)
+                        {
+                            rc = pfnEntryPoint(42);
+                            if (rc == 42)
+                            {
+                                printf("tst-3-driver: success.\n");
+                            }
+                            else
+                                Failure("pfnEntryPoint(42) -> %d (2nd)\n", rc);
+                        }
+                        else
+                            Failure("kLdrModRelocateBits(,,, + 0x22000,,,) -> %#x (%s)\n", rc, kErrName(rc));
+                    }
+                    else
+                        Failure("kLdrModRelocateBits(,, + 0x22000,,,,) -> %#x (%s)\n", rc, kErrName(rc));
+                }
+                else
+                    Failure("pfnEntryPoint(42) -> %d (1st)\n", rc);
+            }
+            else
+                Failure("kLdrModQuerySymbol -> %#x (%s)\n", rc, kErrName(rc));
+        }
+        else
+            Failure("kLdrModGetBits -> %#x (%s)\n", rc, kErrName(rc));
+        free(pvBits);
+    }
+    else
+        Failure("malloc(%lx) -> NULL\n", (long)cbImage);
+
+    /* clean up */
+    rc = kLdrModClose(pMod);
+    if (rc)
+        Failure("kLdrModOpen(%s,) -> %#x (%s)\n", pszFile, rc, kErrName(rc));
+    return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+    int i;
+
+    /*
+     * Test all the given modules (requires arguments).
+     */
+    for (i = 1; i < argc; i++)
+    {
+        TestModule(argv[i]);
+    }
+
+
+    /*
+     * Summary
+     */
+    if (!g_cErrors)
+        printf("tst-3-driver: SUCCESS\n");
+    else
+        printf("tst-3-driver: FAILURE - %d errors\n", g_cErrors);
+    return !!g_cErrors;
+}
Index: /trunk/kLdr/testcase/tst-3-ext.c
===================================================================
--- /trunk/kLdr/testcase/tst-3-ext.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-3-ext.c	(revision 2)
@@ -0,0 +1,35 @@
+/* $Id$ */
+/** @file
+ * kLdr - Dynamic Loader testcase no. 3, 2nd object module.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "tst.h"
+
+extern int g_i1;
+
+int Tst3Sub(int iFortyTwo)
+{
+    return iFortyTwo * 11 * g_i1;
+}
+
Index: /trunk/kLdr/testcase/tst-3-imp-os2.def
===================================================================
--- /trunk/kLdr/testcase/tst-3-imp-os2.def	(revision 2)
+++ /trunk/kLdr/testcase/tst-3-imp-os2.def	(revision 2)
@@ -0,0 +1,30 @@
+; $Id$
+;; @file
+; kLdr - Dynamic Loader testcase no. 3, Fake module import library - OS/2.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+;
+;
+
+LIBRARY tst-3-imp
+EXPORTS
+    _Tst3Ext
+
Index: /trunk/kLdr/testcase/tst-3-imp-win.def
===================================================================
--- /trunk/kLdr/testcase/tst-3-imp-win.def	(revision 2)
+++ /trunk/kLdr/testcase/tst-3-imp-win.def	(revision 2)
@@ -0,0 +1,30 @@
+; $Id$
+;; @file
+; kLdr - Dynamic Loader testcase no. 3, Fake module import library - Windows.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+;
+;
+
+LIBRARY tst-3-imp
+EXPORTS
+    Tst3Ext
+
Index: /trunk/kLdr/testcase/tst-3.c
===================================================================
--- /trunk/kLdr/testcase/tst-3.c	(revision 2)
+++ /trunk/kLdr/testcase/tst-3.c	(revision 2)
@@ -0,0 +1,74 @@
+/* $Id$ */
+/** @file
+ * kLdr - Dynamic Loader testcase no. 3, Driver.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "tst.h"
+
+
+int g_i1 = 1;
+int g_i2 = 2;
+int *g_pi1 = &g_i1;
+
+extern int Tst3Sub(int);
+int (*g_pfnTst3Sub)(int) = &Tst3Sub;
+
+MY_IMPORT(int) Tst3Ext(int);
+int (*g_pfnTst3Ext)(int) = &Tst3Ext;
+
+char g_achBss[256];
+
+
+MY_EXPORT(int) Tst3(int iFortyTwo)
+{
+    int rc;
+
+    if (iFortyTwo != 42)
+        return 0;
+    if (g_i1 != 1)
+        return 1;
+    if (g_i2 != 2)
+        return 2;
+    if (g_pi1 != &g_i1)
+        return 3;
+    if (g_pfnTst3Sub != &Tst3Sub)
+        return 4;
+    rc = Tst3Sub(iFortyTwo);
+    if (rc != g_pfnTst3Sub(iFortyTwo))
+        return 5;
+    rc = Tst3Ext(iFortyTwo);
+    if (rc != 42)
+        return 6;
+    rc = g_pfnTst3Ext(iFortyTwo);
+    if (rc != 42)
+        return 7;
+    for (rc = 0; rc < sizeof(g_achBss); rc++)
+        if (g_achBss[rc])
+            return 8;
+    if (g_achBss[0] || g_achBss[1] || g_achBss[255])
+        return 9;
+
+    return 42;
+}
+
Index: /trunk/kLdr/testcase/tst.h
===================================================================
--- /trunk/kLdr/testcase/tst.h	(revision 2)
+++ /trunk/kLdr/testcase/tst.h	(revision 2)
@@ -0,0 +1,53 @@
+/* $Id$ */
+/** @file
+ * kLdr testcase header.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___tst_h___
+#define ___tst_h___
+
+#include <k/kLdr.h>
+#include <k/kHlp.h>
+
+#if K_OS == K_OS_OS2 \
+ || K_OS == K_OS_WINDOWS
+# define MY_EXPORT(type) __declspec(dllexport) type
+/*# define MY_IMPORT(type) extern __declspec(dllimport) type*/
+# define MY_IMPORT(type) extern type
+#else
+# define MY_EXPORT(type) type
+# define MY_IMPORT(type) extern type
+#endif
+
+#if K_OS == K_OS_OS2 \
+ || K_OS == K_OS_DARWIN
+# define MY_NAME(a) "_" a
+#else
+# define MY_NAME(a) a
+#endif
+
+extern const char *g_pszName;
+
+#endif
+
Index: /trunk/kLdr/testcase/tstDllMain.c
===================================================================
--- /trunk/kLdr/testcase/tstDllMain.c	(revision 2)
+++ /trunk/kLdr/testcase/tstDllMain.c	(revision 2)
@@ -0,0 +1,188 @@
+/* $Id$ */
+/** @file
+ * kLdr testcase.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "tst.h"
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# include <os2.h>
+# include <string.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <windows.h>
+# include <string.h>
+
+#elif K_OS == K_OS_DARWIN
+# include <unistd.h>
+# include <string.h>
+
+#else
+# error "port me"
+#endif
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+void tstWrite(const char *psz);
+
+
+
+#if K_OS == K_OS_OS2
+/**
+ * OS/2 DLL 'main'
+ */
+ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlags)
+{
+    switch (fFlags)
+    {
+        case 0:
+            tstWrite("init: ");
+            tstWrite(g_pszName);
+            tstWrite("\n");
+            return TRUE;
+
+        case 1:
+            tstWrite("term: ");
+            tstWrite(g_pszName);
+            tstWrite("\n");
+            return TRUE;
+
+        default:
+            tstWrite("!invalid!: ");
+            tstWrite(g_pszName);
+            tstWrite("\n");
+            return FALSE;
+    }
+}
+
+#elif K_OS == K_OS_WINDOWS
+
+/**
+ * OS/2 DLL 'main'
+ */
+BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)
+{
+    switch (dwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            tstWrite("init: ");
+            tstWrite(g_pszName);
+            tstWrite("\n");
+            return TRUE;
+
+        case DLL_PROCESS_DETACH:
+            tstWrite("term: ");
+            tstWrite(g_pszName);
+            tstWrite("\n");
+            return TRUE;
+
+        case DLL_THREAD_ATTACH:
+            tstWrite("thread init: ");
+            tstWrite(g_pszName);
+            tstWrite("\n");
+            return TRUE;
+
+        case DLL_THREAD_DETACH:
+            tstWrite("thread term: ");
+            tstWrite(g_pszName);
+            tstWrite("\n");
+            return TRUE;
+
+        default:
+            tstWrite("!invalid!: ");
+            tstWrite(g_pszName);
+            tstWrite("\n");
+            return FALSE;
+    }
+}
+
+#elif K_OS == K_OS_DARWIN
+/* later */
+
+#else
+# error "port me"
+#endif
+
+
+/**
+ * Writes a string with unix lineendings.
+ *
+ * @param   pszMsg  The string.
+ */
+void tstWrite(const char *pszMsg)
+{
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+    /*
+     * Line by line.
+     */
+    ULONG       cbWritten;
+    const char *pszNl = strchr(pszMsg, '\n');
+
+    while (pszNl)
+    {
+        cbWritten = pszNl - pszMsg;
+
+#if K_OS == K_OS_OS2
+        if (cbWritten)
+            DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten);
+        DosWrite((HFILE)2, "\r\n", 2, &cbWritten);
+#else
+        if (cbWritten)
+            WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL);
+        WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL);
+#endif
+
+        /* next */
+        pszMsg = pszNl + 1;
+        pszNl = strchr(pszMsg, '\n');
+    }
+
+    /*
+     * Remaining incomplete line.
+     */
+    if (*pszMsg)
+    {
+        cbWritten = strlen(pszMsg);
+#if K_OS == K_OS_OS2
+        DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten);
+#else
+        WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL);
+#endif
+    }
+
+#elif K_OS == K_OS_DARWIN
+    write(STDERR_FILENO, pszMsg, strlen(pszMsg));
+
+#else
+# error "port me"
+#endif
+}
+
+
Index: /trunk/kLdr/testcase/tstDllMainStub-os2.asm
===================================================================
--- /trunk/kLdr/testcase/tstDllMainStub-os2.asm	(revision 2)
+++ /trunk/kLdr/testcase/tstDllMainStub-os2.asm	(revision 2)
@@ -0,0 +1,36 @@
+; $Id$
+;; @file
+; kLdr - OS/2 entry point thingy...
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+;
+;
+
+segment TEXT32 public CLASS=CODE align=16 use32
+extern _DLL_InitTerm
+..start:
+    jmp _DLL_InitTerm
+
+segment DATA32 stack CLASS=DATA align=16 use32
+
+global WEAK$ZERO
+WEAK$ZERO EQU 0
+
Index: /trunk/kLdr/testcase/tstDllMainStub.c
===================================================================
--- /trunk/kLdr/testcase/tstDllMainStub.c	(revision 2)
+++ /trunk/kLdr/testcase/tstDllMainStub.c	(revision 2)
@@ -0,0 +1,72 @@
+/* $Id$ */
+/** @file
+ * kLdr testcase - DLL Stub.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "tst.h"
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# include <windows.h>
+
+#elif K_OS == K_OS_DARWIN
+/* later */
+
+#else
+# error "port me"
+#endif
+
+
+#if K_OS == K_OS_OS2
+/**
+ * OS/2 DLL 'main'
+ */
+ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlag)
+{
+    return TRUE;
+}
+
+#elif K_OS == K_OS_WINDOWS
+
+/**
+ * Window DLL 'main'
+ */
+BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)
+{
+    return TRUE;
+}
+
+#elif K_OS == K_OS_DARWIN
+/* later */
+
+#else
+# error "port me"
+#endif
+
Index: /trunk/kLdr/testcase/tstExeMainStub-os2.asm
===================================================================
--- /trunk/kLdr/testcase/tstExeMainStub-os2.asm	(revision 2)
+++ /trunk/kLdr/testcase/tstExeMainStub-os2.asm	(revision 2)
@@ -0,0 +1,36 @@
+; $Id$
+;; @file
+; kLdr - OS/2 entry point thingy...
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+;
+; This file is part of kStuff.
+;
+; kStuff is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; kStuff 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kStuff; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+;
+;
+
+segment TEXT32 public CLASS=CODE align=16 use32
+extern OS2Main
+..start:
+    jmp OS2Main
+
+segment DATA32 stack CLASS=DATA align=16 use32
+
+global WEAK$ZERO
+WEAK$ZERO EQU 0
+
Index: /trunk/kLdr/testcase/tstExeMainStub.c
===================================================================
--- /trunk/kLdr/testcase/tstExeMainStub.c	(revision 2)
+++ /trunk/kLdr/testcase/tstExeMainStub.c	(revision 2)
@@ -0,0 +1,89 @@
+/* $Id$ */
+/** @file
+ * kLdr testcase - DLL Stub.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "tst.h"
+
+#if K_OS == K_OS_OS2
+# define INCL_BASE
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+/* nothing */
+
+#elif K_OS == K_OS_NT
+# include <ddk/ntapi.h> /** @todo fix the nt port. */
+
+#else
+# error "port me"
+#endif
+
+
+extern int main();
+
+
+#if K_OS == K_OS_OS2
+/**
+ * OS/2 'main'.
+ */
+ULONG _System OS2Main(HMODULE hmod, ULONG fFlag, ULONG ulReserved, PSZ pszzEnv, PSZ pszzCmdLine)
+{
+    int rc;
+    rc = main();
+    return rc;
+}
+
+#elif K_OS == K_OS_WINDOWS
+/**
+ * Windows'main'
+ */
+int WindowsMain(void)
+{
+    int rc;
+    rc = main();
+    return rc;
+}
+
+#elif K_OS == K_OS_NT
+/**
+ * Windows NT 'main'
+ */
+VOID NtProcess(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)
+{
+    int rc;
+    rc = main();
+    /* (no way around this) */
+    for (;;)
+        ZwTerminateProcess(NtCurrentProcess(), rc);
+}
+
+#else
+# error "port me"
+#endif
+
+
Index: /trunk/kLdr/tg/KLDRSTATE.txvstc
===================================================================
--- /trunk/kLdr/tg/KLDRSTATE.txvstc	(revision 2)
+++ /trunk/kLdr/tg/KLDRSTATE.txvstc	(revision 2)
@@ -0,0 +1,529 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodeSet version="1.0">
+    <view uin="id83t9setug73fpetug74ah">
+        <property name="$metaclass" value="State Diagram"/>
+        <property name="@__options" value=""/>
+        <reference df-class-name="reference" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="90,40,80,40"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid7iy6aetug73fpetugal1c:id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+                <property name="sourceAnchor" value="130,80"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="130,110"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid14j0oetug73fpetugbmyx:id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+                <property name="sourceAnchor" value="90,70"/>
+                <property name="bendpoints" value="30,70,30,1000"/>
+                <property name="targetAnchor" value="150,1000"/>
+                <property name="bounds_setted_by_user" value="true"/>
+                <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid14j0oetug73fpetugbmyx:id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+                    <property name="bounds" value="10,50,77,16"/>
+                </reference>
+            </reference>
+        </reference>
+        <reference df-class-name="reference1" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4">
+            <property name="$shortcutReference" value="true"/>
+            <property name="background_color" value="0,0,0"/>
+            <property name="bounds" value="120,0,12,12"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4.linkid2j70ketug73fpetug8gs8:id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4">
+                <property name="sourceAnchor" value="126,12"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="126,40"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference2" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="90,110,80,40"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak.linkid7cno0etug73fpetuganpl:id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak">
+                <property name="sourceAnchor" value="130,150"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="130,190"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak.linkid4elkbetug73fpetugbpa9:id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak">
+                <property name="sourceAnchor" value="90,140"/>
+                <property name="bendpoints" value="30,140,30,990"/>
+                <property name="targetAnchor" value="150,990"/>
+                <property name="bounds_setted_by_user" value="true"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference3" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="320,110,110,40"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkidd5q0etug73fpetugl30f:id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+                <property name="sourceAnchor" value="380,150"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="380,190"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkid2yl8cetug73fpetugl74g:id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+                <property name="sourceAnchor" value="430,140"/>
+                <property name="bendpoints" value="550,140,550,840"/>
+                <property name="targetAnchor" value="284,840"/>
+                <property name="bounds_setted_by_user" value="true"/>
+                <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkid2yl8cetug73fpetugl74g:id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+                    <property name="bounds" value="470,120,77,16"/>
+                </reference>
+            </reference>
+        </reference>
+        <reference df-class-name="reference4" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="80,190,135,40"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l.linkidr4phetug73fpetugcezv:id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l">
+                <property name="sourceAnchor" value="130,230"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="130,270"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l.linkid82puetug73fpetugbwui:id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l">
+                <property name="sourceAnchor" value="80,220"/>
+                <property name="bendpoints" value="30,220,30,980"/>
+                <property name="targetAnchor" value="150,980"/>
+                <property name="bounds_setted_by_user" value="true"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference5" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="90,270,80,40"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj.linkid4fiuhetug73fpetugbs4x:id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj">
+                <property name="sourceAnchor" value="90,300"/>
+                <property name="bendpoints" value="30,300,30,970"/>
+                <property name="targetAnchor" value="150,970"/>
+                <property name="bounds_setted_by_user" value="true"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj.linkid8ewc7etug73fpetughpzu:id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj">
+                <property name="sourceAnchor" value="130,310"/>
+                <property name="bendpoints" value="130,330,190,330"/>
+                <property name="targetAnchor" value="190,350"/>
+                <property name="bounds_setted_by_user" value="true"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference6" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,950,134,60"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg.linkid80127etug73fpetugd66b:id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg">
+                <property name="sourceAnchor" value="210,1010"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,1040"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference7" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,1040,134,40"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e.linkid8h4qnetug73fpetugf6j3:id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e">
+                <property name="sourceAnchor" value="208,1080"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="208,1110"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference8" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,880,134,40"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p.linkid6ngyletug73fpetugehbp:id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p">
+                <property name="sourceAnchor" value="210,920"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,950"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference9" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,790,134,60"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid6vibeetug73fpetugephi:id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+                <property name="sourceAnchor" value="210,850"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,880"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid1izxmetug73fpetugesem:id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+                <property name="sourceAnchor" value="260,790"/>
+                <property name="bendpoints" value="260,770,590,770,590,90,380,90"/>
+                <property name="targetAnchor" value="380,110"/>
+                <property name="bounds_setted_by_user" value="true"/>
+                <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid1izxmetug73fpetugesem:id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+                    <property name="bounds" value="290,750,84,16"/>
+                </reference>
+            </reference>
+        </reference>
+        <reference df-class-name="reference10" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid17bz7etug73fpetugf23i">
+            <property name="$shortcutReference" value="true"/>
+            <property name="background_color" value="0,0,0"/>
+            <property name="bounds" value="200,1110,15,15"/>
+        </reference>
+        <reference df-class-name="reference11" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,380,129,40"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkidy5coetug73fpetughmwy:id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+                <property name="sourceAnchor" value="210,420"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,460"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkid989qmetug73fpetugi623:id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+                <property name="sourceAnchor" value="150,410"/>
+                <property name="bendpoints" value="60,410,60,810"/>
+                <property name="targetAnchor" value="150,810"/>
+                <property name="bounds_setted_by_user" value="true"/>
+                <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkid989qmetug73fpetugi623:id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+                    <property name="bounds" value="50,390,94,16"/>
+                </reference>
+            </reference>
+        </reference>
+        <reference df-class-name="reference12" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,460,134,40"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid7b0d0etug73fpetughibe:id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+                <property name="sourceAnchor" value="284,490"/>
+                <property name="bendpoints" value="460,490"/>
+                <property name="targetAnchor" value="460,540"/>
+                <property name="bounds_setted_by_user" value="true"/>
+                <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid7b0d0etug73fpetughibe:id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+                    <property name="bounds" value="290,490,42,16"/>
+                </reference>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid2yeeuetug73fpetughfff:id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+                <property name="sourceAnchor" value="210,500"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,540"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference13" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,540,134,50"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv.linkid5imvsetug73fpetughcca:id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv">
+                <property name="sourceAnchor" value="210,590"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,630"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference14" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,630,131,40"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid7ockpetuqdc66etuqdq4c:id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+                <property name="sourceAnchor" value="281,650"/>
+                <property name="bendpoints" value="310,650,310,570"/>
+                <property name="targetAnchor" value="284,570"/>
+                <property name="bounds_setted_by_user" value="true"/>
+                <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid7ockpetuqdc66etuqdq4c:id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+                    <property name="bounds" value="290,650,84,16"/>
+                </reference>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid3jvhdetug73fpetugiz5h:id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+                <property name="sourceAnchor" value="210,670"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,710"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference15" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="410,540,121,50"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4.linkidotudetug73fpetugilak:id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4">
+                <property name="sourceAnchor" value="460,590"/>
+                <property name="bendpoints" value="460,910"/>
+                <property name="targetAnchor" value="284,910"/>
+                <property name="bounds_setted_by_user" value="true"/>
+                <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4.linkidotudetug73fpetugilak:id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4">
+                    <property name="bounds" value="470,600,45,16"/>
+                </reference>
+            </reference>
+        </reference>
+        <reference df-class-name="reference16" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="150,710,134,40"/>
+            <property name="bounds_setted_by_user" value="true"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0.linkids5u8etug73fpetugj2bq:id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0">
+                <property name="sourceAnchor" value="210,750"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,790"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference17" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="290,190,189,40"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4.linkid529snetug73fpetuglmq0:id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4">
+                <property name="sourceAnchor" value="479,220"/>
+                <property name="bendpoints" value="550,220,550,830"/>
+                <property name="targetAnchor" value="284,830"/>
+                <property name="bounds_setted_by_user" value="true"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4.linkid733w4etug73fpetuglagw:id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4">
+                <property name="sourceAnchor" value="380,230"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="380,270"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference18" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65">
+            <property name="$shortcutReference" value="true"/>
+            <property name="bounds" value="320,270,118,40"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65.linkidcf8yetug73fpetuglj2g:id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65">
+                <property name="sourceAnchor" value="438,300"/>
+                <property name="bendpoints" value="550,300,550,820"/>
+                <property name="targetAnchor" value="284,820"/>
+                <property name="bounds_setted_by_user" value="true"/>
+            </reference>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65.linkid5watyetug73fpetugle5c:id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65">
+                <property name="sourceAnchor" value="380,310"/>
+                <property name="bendpoints" value="380,330,230,330"/>
+                <property name="targetAnchor" value="230,350"/>
+                <property name="bounds_setted_by_user" value="true"/>
+            </reference>
+        </reference>
+        <reference df-class-name="reference19" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3">
+            <property name="$shortcutReference" value="true"/>
+            <property name="background_color" value="0,0,0"/>
+            <property name="bounds" value="180,350,60,6"/>
+            <reference referencedUin="design:link:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3.linkid4uffpetui3nn8etui6xmx:id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3">
+                <property name="sourceAnchor" value="210,356"/>
+                <property name="bendpoints" value=""/>
+                <property name="targetAnchor" value="210,380"/>
+                <reference referencedUin="linklabel:$transitionInplaceEditing:design:link:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3.linkid4uffpetui3nn8etui6xmx:id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3">
+                    <property name="bounds" value="220,360,122,16"/>
+                </reference>
+            </reference>
+        </reference>
+    </view>
+    <node uin="id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="Open"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid7iy6aetug73fpetugal1c">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd.linkid14j0oetug73fpetugbmyx">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd"/>
+            <property name="$metaclass" value="Transition"/>
+            <property name="$event_name" value="done (failed)"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4">
+        <property name="$metaclass" value="Start State"/>
+        <property name="$name" value="StartState1"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4.linkid2j70ketug73fpetug8gs8">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid4wa62etug73fpetug7hpd"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid67r7zetug73fpetug87g4"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="Mapped"/>
+        <link uin="id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak.linkid7cno0etug73fpetuganpl">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak.linkid4elkbetug73fpetugbpa9">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidd21uetug73fpetug8kak"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="Reloaded"/>
+        <link uin="id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkidd5q0etug73fpetugl30f">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9.linkid2yl8cetug73fpetugl74g">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9"/>
+            <property name="$metaclass" value="Transition"/>
+            <property name="$event_name" value="done (failed)"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="LoadedPrerequisites"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l.linkid82puetug73fpetugbwui">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l.linkidr4phetug73fpetugcezv">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7et8etug73fpetug938l"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="FixedUp"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj.linkid4fiuhetug73fpetugbs4x">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj.linkid8ewc7etug73fpetughpzu">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid71qrcetug73fpetuga3zj"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="PendingDestroy"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg.linkid80127etug73fpetugd66b">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="Destroyed"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e.linkid8h4qnetug73fpetugf6j3">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid17bz7etug73fpetugf23i"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7vd8retug73fpetugcr3e"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="GC"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p.linkid6ngyletug73fpetugehbp">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3wom6etug73fpetugb9cg"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="PendingGC"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid6vibeetug73fpetugephi">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5.linkid1izxmetug73fpetugesem">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidq28metug73fpetug8uf9"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+            <property name="$metaclass" value="Transition"/>
+            <property name="$event_name" value="Loaded again"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid17bz7etug73fpetugf23i">
+        <property name="$metaclass" value="End State"/>
+        <property name="$name" value="EndState1"/>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="PendingInitialization"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkidy5coetug73fpetughmwy">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i.linkid989qmetug73fpetugi623">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i"/>
+            <property name="$metaclass" value="Transition"/>
+            <property name="$event_name" value="Other init failure"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="Initializing"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid2yeeuetug73fpetughfff">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj.linkid7b0d0etug73fpetughibe">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid2vt9ietug73fpetugfjhj"/>
+            <property name="$metaclass" value="Transition"/>
+            <property name="$event_name" value="Failed"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="Good"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv.linkid5imvsetug73fpetughcca">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="PendingTermination"/>
+        <link uin="id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid3jvhdetug73fpetugiz5h">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid7ockpetuqdc66etuqdq4c">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3"/>
+            <property name="$metaclass" value="Transition"/>
+            <property name="$event_name" value="Loaded again"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="InitializationFailed"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4.linkidotudetug73fpetugilak">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid417yeetug73fpetugeb3p"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid3z4oketug73fpetuggjl4"/>
+            <property name="$metaclass" value="Transition"/>
+            <property name="$event_name" value="Do GC"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="Terminating"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0.linkids5u8etug73fpetugj2bq">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid9bbfsetug73fpetugirr0"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="ReloadedLoadedPrerequisites"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4.linkid733w4etug73fpetuglagw">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4.linkid529snetug73fpetuglmq0">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6t6upetug73fpetugj6k4"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65">
+        <property name="$metaclass" value="State"/>
+        <property name="$name" value="ReloadedFixedUp"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65.linkid5watyetug73fpetugle5c">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+        <link uin="id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65.linkidcf8yetug73fpetuglj2g">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid7q41getug73fpetugejq5"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid5e0mxetug73fpetugjk65"/>
+            <property name="$metaclass" value="Transition"/>
+        </link>
+    </node>
+    <node uin="id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3">
+        <property name="$orientation" value="horizontal"/>
+        <property name="$metaclass" value="Synchronization Bar"/>
+        <property name="$name" value="SyncBar1"/>
+        <link uin="id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3.linkid4uffpetui3nn8etui6xmx">
+            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6b4f8etug73fpetugfa3i"/>
+            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid6yrvpetui3nn8etui62p3"/>
+            <property name="$metaclass" value="Transition"/>
+            <property name="$event_name" value="Fixed up all modules"/>
+        </link>
+    </node>
+</nodeSet>
Index: /trunk/kLdr/tg/default.txvpck
===================================================================
--- /trunk/kLdr/tg/default.txvpck	(revision 2)
+++ /trunk/kLdr/tg/default.txvpck	(revision 2)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodeSet version="1.0">
+    <view uin="id309n7etug73fpetug73wh">
+        <property name="$metaclass" value="Package Diagram"/>
+        <property name="@__options" value=""/>
+        <property name="$defaultDiagram" value=""/>
+    </view>
+</nodeSet>
Index: /trunk/kLdr/tg/kLdr.tpr
===================================================================
--- /trunk/kLdr/tg/kLdr.tpr	(revision 2)
+++ /trunk/kLdr/tg/kLdr.tpr	(revision 2)
@@ -0,0 +1,23 @@
+[Project]
+Language=cpp
+Root.0=$PROJECT_DIR$
+Root.0.access=writable
+Root.0.file_types=cpp_source;cpp_header;diagram
+Root.0.package_prefix=
+Version=3.0
+projectfile.encoding=MS932
+Root.1=$TGH$/jdk/jre/lib/rt.jar
+Root.1.access=import
+Root.1.non_removable=
+[workspace]
+Developer.CodingWorkspace={{0,2,-1,0,0,0,0,0,0,1,0,50,75,25,-1,-1,-1,-1}${0,1,-1,0,0,0,0,1,0,1,0,50,75,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,66,50,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,66,50,25,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,5,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,1,66,50,25,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}}
+Developer.DebugWorkspace={{0,2,-1,0,0,0,0,0,0,1,0,50,75,25,-1,-1,-1,-1}${0,1,-1,0,0,0,0,1,0,1,1,50,75,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,0,-1,0,0,0,0,1,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}}
+Developer.DesignWorkspace={{0,2,-1,0,0,0,0,1,0,1,0,50,75,22,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,1,50,50,22,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}}
+Developer.kLdr={{0,2,-1,0,0,0,0,1,0,1,1,50,75,22,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}}
+names.Developer={kLdr,DesignWorkspace,CodingWorkspace,DebugWorkspace}
+[vcs]
+provider.class=CVS LAN
+[lastOpenProjectName]
+Developer=kLdr
+[model]
+showDiagramContents=true
Index: /trunk/kLdr/tg/kLdr.tws
===================================================================
--- /trunk/kLdr/tg/kLdr.tws	(revision 2)
+++ /trunk/kLdr/tg/kLdr.tws	(revision 2)
@@ -0,0 +1,2 @@
+workspace.diagram.active = <oiref:design#Class#id83t9setug73fpetug74ah.diagram:oiref>
+workspace.diagram.open.0 = <oiref:design#Class#id83t9setug73fpetug74ah.diagram:oiref>
Index: /trunk/kLdr/tstkLdrHeap.c
===================================================================
--- /trunk/kLdr/tstkLdrHeap.c	(revision 2)
+++ /trunk/kLdr/tstkLdrHeap.c	(revision 2)
@@ -0,0 +1,226 @@
+/* $Id$ */
+/** @file
+ * kLdr - Heap testcase.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include <k/kHlp.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define CHECK_FATAL(expr) \
+    do { if (!(expr)) { printf("tstkLdrHeap(%d): FATAL FAILURE - %s\n", __LINE__, #expr); return 1; } \
+    } while (0)
+
+#define CHECK(expr) \
+    do { if (!(expr)) { printf("tstkLdrHeap(%d): ERROR - %s\n", __LINE__, #expr); cErrors++; kHlpAssertBreakpoint();} \
+    } while (0)
+
+
+/**
+ * Get a random size.
+ * @returns random size.
+ */
+static unsigned RandSize(void)
+{
+    unsigned i = (unsigned)rand() % (256*1024 - 1);
+    return i ? i : 1;
+}
+
+/**
+ * Get a random index.
+ * @returns random index.
+ * @param   cEntries    The number of entries in the table.
+ */
+static unsigned RandIdx(unsigned cEntries)
+{
+    unsigned i = (unsigned)rand();
+    while (i >= cEntries)
+        i >>= 1;
+    return i;
+}
+
+#if 0
+# define kHlpAlloc(a) malloc(a)
+# define kHlpFree(a) free(a)
+#endif
+
+int main()
+{
+    int cErrors = 0;
+    int rc;
+#define MAX_ALLOCS 256
+    static struct
+    {
+        void *pv;
+        unsigned cb;
+    } s_aAllocs[MAX_ALLOCS];
+    unsigned cAllocs;
+    unsigned i;
+    unsigned j;
+
+    /*
+     * Some simple init / term.
+     */
+    rc = kHlpHeapInit();
+    CHECK_FATAL(!rc);
+    kHlpHeapTerm();
+
+    rc = kHlpHeapInit();
+    CHECK_FATAL(!rc);
+    kHlpHeapTerm();
+
+
+    /*
+     * Simple alloc all, free all in FIFO order.
+     */
+    rc = kHlpHeapInit();
+    CHECK_FATAL(!rc);
+
+    /* 1. allocate all slots. */
+    for (i = 0; i < MAX_ALLOCS; i++)
+    {
+        s_aAllocs[i].cb = RandSize();
+        s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb);
+        CHECK(s_aAllocs[i].pv);
+    }
+
+    /* 2. free all slots. */
+    for (i = 0; i < MAX_ALLOCS; i++)
+        kHlpFree(s_aAllocs[i].pv);
+
+    /* terminate */
+    kHlpHeapTerm();
+
+
+    /*
+     * Simple alloc all, free all in LIFO order.
+     */
+    rc = kHlpHeapInit();
+    CHECK_FATAL(!rc);
+
+    /* 1. allocate all slots. */
+    for (i = 0; i < MAX_ALLOCS; i++)
+    {
+        s_aAllocs[i].cb = RandSize();
+        s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb);
+        CHECK(s_aAllocs[i].pv);
+    }
+
+    /* 2. free all slots. */
+    i = MAX_ALLOCS;
+    while (i-- > 0)
+        kHlpFree(s_aAllocs[i].pv);
+
+    /* terminate */
+    kHlpHeapTerm();
+
+
+    /*
+     * Bunch of allocations, free half, allocate and free in pairs, free all.
+     */
+    rc = kHlpHeapInit();
+    CHECK_FATAL(!rc);
+
+    /* 1. allocate all slots. */
+    for (i = 0; i < MAX_ALLOCS; i++)
+    {
+        s_aAllocs[i].cb = RandSize();
+        s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb);
+        CHECK(s_aAllocs[i].pv);
+    }
+    cAllocs = MAX_ALLOCS;
+
+    /* 2. free half (random order). */
+    while (cAllocs > MAX_ALLOCS / 2)
+    {
+        i = RandIdx(cAllocs);
+        kHlpFree(s_aAllocs[i].pv);
+        cAllocs--;
+        if (i != cAllocs)
+            s_aAllocs[i] = s_aAllocs[cAllocs];
+    }
+
+    /* 3. lots of alloc and free activity. */
+    for (j = 0; j < MAX_ALLOCS * 32; j++)
+    {
+        /* allocate */
+        unsigned cMax = RandIdx(MAX_ALLOCS / 4) + 1;
+        while (cAllocs < MAX_ALLOCS && cMax-- > 0)
+        {
+            i = cAllocs;
+            s_aAllocs[i].cb = RandSize();
+            s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb);
+            CHECK(s_aAllocs[i].pv);
+            cAllocs++;
+        }
+
+        /* free */
+        cMax = RandIdx(MAX_ALLOCS / 4) + 1;
+        while (cAllocs > MAX_ALLOCS / 2 && cMax-- > 0)
+        {
+            i = RandIdx(cAllocs);
+            kHlpFree(s_aAllocs[i].pv);
+            cAllocs--;
+            if (i != cAllocs)
+                s_aAllocs[i] = s_aAllocs[cAllocs];
+        }
+    }
+
+    /* 4. free all */
+    while (cAllocs > 0)
+    {
+        i = RandIdx(cAllocs);
+        kHlpFree(s_aAllocs[i].pv);
+        cAllocs--;
+        if (i != cAllocs)
+            s_aAllocs[i] = s_aAllocs[cAllocs];
+    }
+
+    /* terminate */
+    kHlpHeapTerm();
+
+
+    /* summary */
+    if (!cErrors)
+        printf("tstkLdrHeap: SUCCESS\n");
+    else
+        printf("tstkLdrHeap: FAILURE - %d errors\n", cErrors);
+    return !!cErrors;
+}
Index: /trunk/kLdr/tstkLdrMod.c
===================================================================
--- /trunk/kLdr/tstkLdrMod.c	(revision 2)
+++ /trunk/kLdr/tstkLdrMod.c	(revision 2)
@@ -0,0 +1,631 @@
+/* $Id$ */
+/** @file
+ * kLdr - Module interpreter testcase.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kLdr.h>
+#include <k/kErr.h>
+#include <k/kErrors.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** The default base address used in the tests. */
+#define MY_BASEADDRESS      0x2400000
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The numbers of errors. */
+static int g_cErrors = 0;
+
+
+
+/**
+ * Report failure.
+ */
+static int Failure(const char *pszFormat, ...)
+{
+    va_list va;
+
+    g_cErrors++;
+
+    printf("tstLdrMod: ");
+    va_start(va, pszFormat);
+    vprintf(pszFormat, va);
+    va_end(va);
+    printf("\n");
+    return 1;
+}
+
+
+/** Dummy import resolver callback. */
+static int BasicTestsGetImport(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
+                               const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser)
+{
+    *puValue = 0xdeadface;
+    *pfKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE;
+    return 0;
+}
+
+
+/**
+ * Verbose memcmp().
+ */
+static int TestMemComp(const void *pv1, const void *pv2, KSIZE cb)
+{
+    KSIZE           off;
+    const KU8      *pb1 = (const KU8 *)pv1;
+    const KU8      *pb2 = (const KU8 *)pv2;
+    if (!memcmp(pb1, pb2, cb))
+        return 0;
+    printf("Mismatching blocks pv1=%p pv2=%p cb=%#x:\n", pv1, pv2, cb);
+    for (off = 0; off < cb; off++)
+    {
+        if (pb1[off] == pb2[off])
+            continue;
+        printf("%08x %02x != %02x\n", off, pb1[off], pb2[off]);
+    }
+    return memcmp(pb1, pb2, cb); /* lazy */
+}
+
+
+/**
+ * Performs basic relocation tests.
+ */
+static int BasicTestsRelocate(PKLDRMOD pMod, void *pvBits, void *pvBits2)
+{
+    const KSIZE cbImage = (KSIZE)kLdrModSize(pMod);
+    int rc;
+
+    printf("* Relocation test...\n");
+
+    /*
+     * Get the same bits again to check that we get the same result.
+     */
+    memset(pvBits2, 0xfe, cbImage);
+    rc = kLdrModGetBits(pMod, pvBits2, (KUPTR)pvBits, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to get image bits, rc=%d (%s) (a)", rc, kErrName(rc));
+    if (TestMemComp(pvBits2, pvBits, cbImage))
+        return Failure("relocation test failed, mismatching bits (a)");
+
+    /*
+     * Short relocation round trip.
+     */
+    rc = kLdrModRelocateBits(pMod, pvBits2, 0x1000, (KUPTR)pvBits, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to relocate, rc=%d (%s) (b1)", rc, kErrName(rc));
+    rc = kLdrModRelocateBits(pMod, pvBits2, (KUPTR)pvBits, 0x1000, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to relocate, rc=%d (%s) (b2)", rc, kErrName(rc));
+    if (TestMemComp(pvBits2, pvBits, cbImage))
+        return Failure("relocation test failed, mismatching bits (b)");
+
+    /*
+     * Longer trip where we also check the intermediate results.
+     */
+    /* stage one */
+    rc = kLdrModRelocateBits(pMod, pvBits, 0x1000000, (KUPTR)pvBits, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to relocate, rc=%d (%s) (c1)", rc, kErrName(rc));
+    memset(pvBits2, 0xfe, cbImage);
+    rc = kLdrModGetBits(pMod, pvBits2, 0x1000000, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to get image bits, rc=%d (%s) (c1)", rc, kErrName(rc));
+    if (TestMemComp(pvBits2, pvBits, cbImage))
+        return Failure("relocation test failed, mismatching bits (c1)");
+
+    /* stage two */
+    rc = kLdrModRelocateBits(pMod, pvBits, ~(KUPTR)0x1010000, 0x1000000, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to relocate, rc=%d (%s) (c2)", rc, kErrName(rc));
+    memset(pvBits2, 0xef, cbImage);
+    rc = kLdrModGetBits(pMod, pvBits2, ~(KUPTR)0x1010000, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to get image bits, rc=%d (%s) (c2)", rc, kErrName(rc));
+    if (TestMemComp(pvBits2, pvBits, cbImage))
+        return Failure("relocation test failed, mismatching bits (c2)");
+
+    /* stage three */
+    rc = kLdrModRelocateBits(pMod, pvBits, MY_BASEADDRESS, ~(KUPTR)0x1010000, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to relocate, rc=%d (%s) (c3)", rc, kErrName(rc));
+    memset(pvBits2, 0xef, cbImage);
+    rc = kLdrModGetBits(pMod, pvBits2, MY_BASEADDRESS, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to get image bits, rc=%d (%s) (c3)", rc, kErrName(rc));
+    if (TestMemComp(pvBits2, pvBits, cbImage))
+        return Failure("relocation test failed, mismatching bits (c3)");
+
+    /* stage four */
+    rc = kLdrModRelocateBits(pMod, pvBits, ~(KUPTR)0 / 2 - 0x10000, MY_BASEADDRESS, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to relocate, rc=%d %(s) (c4)", rc, kErrName(rc));
+    memset(pvBits2, 0xdc, cbImage);
+    rc = kLdrModGetBits(pMod, pvBits2, ~(KUPTR)0 / 2 - 0x10000, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to get image bits, rc=%d (%s) (c4)", rc, kErrName(rc));
+    if (TestMemComp(pvBits2, pvBits, cbImage))
+        return Failure("relocation test failed, mismatching bits (c4)");
+
+    /* return */
+    rc = kLdrModRelocateBits(pMod, pvBits, (KUPTR)pvBits, ~(KUPTR)0 / 2 - 0x10000, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to relocate, rc=%d (%s) (c5)", rc, kErrName(rc));
+    memset(pvBits2, 0xcd, cbImage);
+    rc = kLdrModGetBits(pMod, pvBits2, (KUPTR)pvBits, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to get image bits, rc=%d (%s) (c5)", rc, kErrName(rc));
+    if (TestMemComp(pvBits2, pvBits, cbImage))
+        return Failure("relocation test failed, mismatching bits (c5)");
+
+    return 0;
+}
+
+
+/**
+ * Dump symbols and check that we can query each of them recursivly.
+ */
+static int BasicTestsEnumSymCallback(PKLDRMOD pMod, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
+                                     const char *pszVersion, KLDRADDR uValue, KU32 fKind, void *pvUser)
+{
+    KLDRADDR    uValue2;
+    KU32        fKind2;
+    int         rc;
+
+    /* dump */
+    printf("#0x%08x: %016" PRI_KLDRADDR " %#08x", iSymbol, uValue, fKind);
+    if (pchSymbol)
+        printf(" %.*s", cchSymbol, pchSymbol);
+    printf("\n");
+
+    /* query by ordinal */
+    if (iSymbol != NIL_KLDRMOD_SYM_ORDINAL)
+    {
+        fKind2 = 0;
+        rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, iSymbol, NULL, 0, NULL, NULL, NULL,
+                                &uValue2, &fKind2);
+        if (rc)
+            return Failure("Couldn't find symbol %#x (%.*s) by ordinal. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kErrName(rc));
+        if (uValue != uValue2)
+            return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/ord)  pvBits=%p",
+                           iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser);
+        if (fKind != fKind2)
+            return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/ord) pvBits=%p",
+                           iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser);
+    }
+
+    /* query by name. */
+    if (pchSymbol)
+    {
+        fKind2 = 0;
+        rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, pchSymbol, cchSymbol, pszVersion,
+                                NULL, NULL, &uValue2, &fKind2);
+        if (rc)
+            return Failure("Couldn't find symbol %#x (%.*s) by name. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kErrName(rc));
+        if (uValue != uValue2)
+            return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/name) pvBits=%p",
+                           iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser);
+        if (fKind != fKind2)
+            return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/name) pvBits=%p",
+                           iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser);
+    }
+
+    return 0;
+}
+
+
+/**
+ * Dump debugger information and check it for correctness.
+ */
+static int BasicTestEnumDbgInfoCallback(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType,
+                                        KI16 iMajorVer, KI16 iMinorVer, KLDRFOFF offFile, KLDRADDR LinkAddress,
+                                        KLDRSIZE cb, const char *pszExtFile, void *pvUser)
+{
+    printf("#0x%08x: enmType=%d %d.%d offFile=0x%" PRI_KLDRADDR " LinkAddress=%" PRI_KLDRADDR " cb=%" PRI_KLDRSIZE " pvUser=%p\n",
+           iDbgInfo, enmType, iMajorVer, iMinorVer, (KLDRADDR)offFile, LinkAddress, cb, pvUser);
+    if (pszExtFile)
+        printf("            pszExtFile=%p '%s'\n", pszExtFile, pszExtFile);
+
+    if (enmType >= KLDRDBGINFOTYPE_END || enmType <= KLDRDBGINFOTYPE_INVALID)
+        return Failure("Bad enmType");
+    if (pvUser != NULL)
+        return Failure("pvUser");
+
+    return 0;
+}
+
+
+/**
+ * Performs the basic module loader test on the specified module and image bits.
+ */
+static int BasicTestsSub2(PKLDRMOD pMod, void *pvBits)
+{
+    KI32 cImports;
+    KI32 i;
+    int rc;
+    KU32 fKind;
+    KLDRADDR Value;
+    KLDRADDR MainEPAddress;
+    KLDRSTACKINFO StackInfo;
+
+    printf("* Testing queries with pvBits=%p...\n", pvBits);
+
+    /*
+     * Get the import modules.
+     */
+    cImports = kLdrModNumberOfImports(pMod, pvBits);
+    printf("cImports=%d\n", cImports);
+    if (cImports < 0)
+        return Failure("failed to query the number of import, cImports=%d", cImports);
+    for (i = 0; i < cImports; i++)
+    {
+        char szImportModule[260];
+        rc = kLdrModGetImport(pMod, pvBits, i, szImportModule, sizeof(szImportModule));
+        if (rc)
+            return Failure("failed to get import module name, rc=%d (%s). (%.260s)", rc, kErrName(rc), szImportModule);
+        printf("import #%d: '%s'\n", i, szImportModule);
+    }
+
+    /*
+     * Query stack info.
+     */
+    StackInfo.Address = ~(KLDRADDR)42;
+    StackInfo.LinkAddress = ~(KLDRADDR)42;
+    StackInfo.cbStack = ~(KLDRSIZE)42;
+    StackInfo.cbStackThread = ~(KLDRSIZE)42;
+    rc = kLdrModGetStackInfo(pMod, pvBits, MY_BASEADDRESS, &StackInfo);
+    if (rc)
+        return Failure("kLdrModGetStackInfo failed with rc=%d (%s)", rc, kErrName(rc));
+    printf("Stack: Address=%016" PRI_KLDRADDR "   LinkAddress=%016" PRI_KLDRADDR "\n"
+           "       cbStack=%016" PRI_KLDRSIZE " cbStackThread=%016" PRI_KLDRSIZE "\n",
+           StackInfo.Address, StackInfo.LinkAddress, StackInfo.cbStack, StackInfo.cbStackThread);
+    if (StackInfo.Address == ~(KLDRADDR)42)
+        return Failure("Bad StackInfo.Address");
+    if (StackInfo.LinkAddress == ~(KLDRADDR)42)
+        return Failure("Bad StackInfo.LinkAddress");
+    if (StackInfo.cbStack == ~(KLDRSIZE)42)
+        return Failure("Bad StackInfo.cbStack");
+    if (StackInfo.cbStackThread == ~(KLDRSIZE)42)
+        return Failure("Bad StackInfo.cbStackThread");
+
+    /*
+     * Query entrypoint.
+     */
+    MainEPAddress = ~(KLDRADDR)42;
+    rc = kLdrModQueryMainEntrypoint(pMod, pvBits, MY_BASEADDRESS, &MainEPAddress);
+    if (rc)
+        return Failure("kLdrModQueryMainEntrypoint failed with rc=%d (%s)", rc, kErrName(rc));
+    printf("Entrypoint: %016" PRI_KLDRADDR "\n", MainEPAddress);
+    if (MainEPAddress == ~(KLDRADDR)42)
+        return Failure("MainEPAddress wasn't set.");
+    if (MainEPAddress != NIL_KLDRADDR && MainEPAddress < MY_BASEADDRESS)
+        return Failure("Bad MainEPAddress (a).");
+    if (MainEPAddress != NIL_KLDRADDR && MainEPAddress >= MY_BASEADDRESS + kLdrModSize(pMod))
+        return Failure("Bad MainEPAddress (b).");
+
+    /*
+     * Debugger information.
+     */
+    rc = kLdrModHasDbgInfo(pMod, pvBits);
+    if (!rc)
+        printf("Has Debugger Information\n");
+    else if (rc == KLDR_ERR_NO_DEBUG_INFO)
+        printf("NO Debugger Information\n");
+    else
+        return Failure("kLdrModHasDbgInfo failed with rc=%d (%s)", rc, kErrName(rc));
+    rc = kLdrModEnumDbgInfo(pMod, pvBits, BasicTestEnumDbgInfoCallback, NULL);
+    if (rc)
+        return Failure("kLdrModEnumDbgInfo failed with rc=%d (%s)", rc, kErrName(rc));
+
+
+    /*
+     * Negative symbol query tests.
+     */
+    fKind = 0;
+    Value = 0x0badc0de;
+    rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL - 20, NULL, 0, NULL, NULL, NULL,
+                            &Value, &fKind);
+    if (rc)
+    {
+        if (Value != 0)
+            return Failure("Value wasn't cleared on failure.");
+    }
+
+    fKind = 0;
+    Value = 0x0badc0de;
+    rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, NULL, 0, NULL, NULL, NULL,
+                            &Value, &fKind);
+    if (!rc)
+        return Failure("NIL ordinal succeeded!");
+    if (Value != 0)
+        return Failure("Value wasn't cleared on failure.");
+
+    /*
+     * Enumerate and query all symbols.
+     */
+    printf("\n"
+           "Symbols:\n");
+    rc = kLdrModEnumSymbols(pMod, pvBits, MY_BASEADDRESS, 0, BasicTestsEnumSymCallback, pvBits);
+    if (rc)
+        return Failure("kLdrModEnumSymbols failed with rc=%d (%s)", rc, kErrName(rc));
+
+
+/*int     kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu);
+*/
+
+    return 0;
+}
+
+
+/**
+ * Performs the basic module loader test on the specified module
+ */
+static int BasicTestsSub(PKLDRMOD pMod)
+{
+    int         rc;
+    KU32        i;
+    void       *pvBits;
+    KSIZE       cbImage;
+
+    /*
+     * Check/dump the module structure.
+     */
+    printf("pMod=%p u32Magic=%#x cSegments=%d\n", (void *)pMod, pMod->u32Magic, pMod->cSegments);
+    printf("enmType=%d enmFmt=%d enmArch=%d enmCpu=%d enmEndian=%d\n",
+           pMod->enmType, pMod->enmFmt, pMod->enmArch, pMod->enmCpu, pMod->enmEndian);
+    printf("Filename: %s (%d bytes)\n", pMod->pszFilename, pMod->cchFilename);
+    printf("    Name: %s (%d bytes)\n", pMod->pszName, pMod->cchName);
+    printf("\n");
+
+    if (pMod->u32Magic != KLDRMOD_MAGIC)
+        return Failure("Bad u32Magic");
+    if (strlen(pMod->pszFilename) != pMod->cchFilename)
+        return Failure("Bad cchFilename");
+    if (strlen(pMod->pszName) != pMod->cchName)
+        return Failure("Bad cchName");
+    if (pMod->enmFmt >= KLDRFMT_END || pMod->enmFmt <= KLDRFMT_INVALID)
+        return Failure("Bad enmFmt");
+    if (pMod->enmType >= KLDRTYPE_END || pMod->enmType <= KLDRTYPE_INVALID)
+        return Failure("Bad enmType: %d", pMod->enmType);
+    if (!K_ARCH_IS_VALID(pMod->enmArch))
+        return Failure("Bad enmArch");
+    if (pMod->enmCpu >= KCPU_END || pMod->enmCpu <= KCPU_INVALID)
+        return Failure("Bad enmCpu");
+    if (pMod->enmEndian >= KLDRENDIAN_END || pMod->enmEndian <= KLDRENDIAN_INVALID)
+        return Failure("Bad enmEndian");
+
+    for (i = 0; i < pMod->cSegments; i++)
+    {
+        printf("seg #%d: pvUser=%p enmProt=%d Name: '%.*s' (%d bytes)\n",
+               i, pMod->aSegments[i].pvUser, pMod->aSegments[i].enmProt,
+               pMod->aSegments[i].cchName, pMod->aSegments[i].pchName, pMod->aSegments[i].cchName);
+        printf("LinkAddress: %016" PRI_KLDRADDR "       cb: %016" PRI_KLDRSIZE "  Alignment=%08" PRI_KLDRADDR " \n",
+               pMod->aSegments[i].LinkAddress, pMod->aSegments[i].cb, pMod->aSegments[i].Alignment);
+        printf("        RVA: %016" PRI_KLDRADDR " cbMapped: %016" PRI_KLDRSIZE " MapAddress=%p\n",
+               pMod->aSegments[i].RVA, (KLDRSIZE)pMod->aSegments[i].cbMapped, (void *)pMod->aSegments[i].MapAddress);
+        printf("    offFile: %016" PRI_KLDRADDR "   cbFile: %016" PRI_KLDRSIZE "\n",
+               (KLDRADDR)pMod->aSegments[i].offFile, (KLDRSIZE)pMod->aSegments[i].cbFile);
+        printf("\n");
+
+        if (pMod->aSegments[i].pvUser != NULL)
+            return Failure("Bad pvUser");
+        if (pMod->aSegments[i].enmProt >= KPROT_END || pMod->aSegments[i].enmProt <= KPROT_INVALID)
+            return Failure("Bad enmProt");
+        if (pMod->aSegments[i].MapAddress != 0)
+            return Failure("Bad MapAddress");
+        if (pMod->aSegments[i].cbMapped < pMod->aSegments[i].cb)
+            return Failure("Bad cbMapped (1)");
+        if (pMod->aSegments[i].cbMapped && !pMod->aSegments[i].Alignment)
+            return Failure("Bad cbMapped (2)");
+        if (pMod->aSegments[i].cbMapped > kLdrModSize(pMod))
+            return Failure("Bad cbMapped (3)");
+        if (    pMod->aSegments[i].Alignment
+            &&  (pMod->aSegments[i].RVA & (pMod->aSegments[i].Alignment - 1)))
+            return Failure("Bad RVA (1)");
+        if (pMod->aSegments[i].RVA != NIL_KLDRADDR && !pMod->aSegments[i].Alignment)
+            return Failure("Bad RVA (2)");
+        if (    pMod->aSegments[i].RVA != NIL_KLDRADDR
+            &&  pMod->aSegments[i].RVA >= kLdrModSize(pMod))
+            return Failure("Bad RVA (3)");
+        if (    pMod->aSegments[i].RVA != NIL_KLDRADDR
+            &&  pMod->aSegments[i].RVA + pMod->aSegments[i].cbMapped > kLdrModSize(pMod))
+            return Failure("Bad RVA/cbMapped (4)");
+        if (pMod->aSegments[i].LinkAddress != NIL_KLDRADDR && !pMod->aSegments[i].Alignment)
+            return Failure("Bad LinkAddress");
+        if (    pMod->aSegments[i].LinkAddress != NIL_KLDRADDR
+            &&  (pMod->aSegments[i].LinkAddress) & (pMod->aSegments[i].Alignment - 1))
+            return Failure("Bad LinkAddress alignment");
+        if (pMod->aSegments[i].offFile != -1 && pMod->aSegments[i].cbFile == -1)
+            return Failure("Bad offFile");
+        if (pMod->aSegments[i].offFile == -1 && pMod->aSegments[i].cbFile != -1)
+            return Failure("Bad cbFile");
+    }
+
+
+    /*
+     * Get image the size and query the image bits.
+     */
+    printf("* Testing user mapping...\n");
+
+    cbImage = (KSIZE)kLdrModSize(pMod);
+    if (cbImage != kLdrModSize(pMod))
+        return Failure("aborting test because the image is too huge!");
+    pvBits = malloc((KSIZE)cbImage);
+    if (!pvBits)
+        return Failure("failed to allocate %d bytes for the image", cbImage);
+
+    rc = kLdrModGetBits(pMod, pvBits, (KUPTR)pvBits, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("failed to get image bits, rc=%d (%s)", rc, kErrName(rc));
+
+    /*
+     * Another cleanup nesting.
+     */
+    rc = BasicTestsSub2(pMod, pvBits);
+    if (!rc)
+    {
+        /*
+         * Test relocating the bits in a few different ways before we're done with them.
+         */
+        void *pvBits2 = malloc((KSIZE)cbImage);
+        if (pvBits2)
+        {
+            rc = BasicTestsRelocate(pMod, pvBits, pvBits2);
+            free(pvBits2);
+        }
+        else
+            rc = Failure("failed to allocate %d bytes for the 2nd image", cbImage);
+    }
+
+    free(pvBits);
+    return rc;
+}
+
+
+/**
+ * Tests the mapping related api, after mapping.
+ */
+static int BasicTestsSubMap2(PKLDRMOD pMod)
+{
+    int rc;
+
+    rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("kLdrModFixupMapping (a) failed, rc=%d (%s)", rc, kErrName(rc));
+
+    rc = kLdrModReload(pMod);
+    if (rc)
+        return Failure("kLdrModReload (a) failed, rc=%d (%s)", rc, kErrName(rc));
+
+    rc = kLdrModReload(pMod);
+    if (rc)
+        return Failure("kLdrModReload (b) failed, rc=%d (%s)", rc, kErrName(rc));
+
+    rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL);
+    if (rc)
+        return Failure("kLdrModFixupMapping (b) failed, rc=%d (%s)", rc, kErrName(rc));
+
+    rc = kLdrModAllocTLS(pMod);
+    if (rc)
+        return Failure("kLdrModAllocTLS (a) failed, rc=%d (%s)", rc, kErrName(rc));
+    kLdrModFreeTLS(pMod);
+
+    rc = kLdrModAllocTLS(pMod);
+    if (rc)
+        return Failure("kLdrModAllocTLS (b) failed, rc=%d (%s)", rc, kErrName(rc));
+    kLdrModFreeTLS(pMod);
+
+    /*
+     * Repeat the BasicTestsSub2 with pvBits as NULL to test module
+     * interpreters that can utilize the mapping.
+     */
+    rc = BasicTestsSub2(pMod, NULL);
+    if (rc)
+        return Failure("BasicTestsSub2 in Map2 failed, rc=%d (%s)", rc, kErrName(rc));
+    return 0;
+}
+
+
+/**
+ * Tests the mapping related api.
+ */
+static int BasicTestsSubMap(PKLDRMOD pMod)
+{
+    int rc, rc2;
+    printf("* Mapping tests...\n");
+
+    rc = kLdrModMap(pMod);
+    if (rc)
+        return Failure("kLdrModMap failed, rc=%d (%s)", rc, kErrName(rc));
+    rc = BasicTestsSubMap2(pMod);
+    rc2 = kLdrModUnmap(pMod);
+    if (rc2)
+    {
+        Failure("kLdrModUnmap failed, rc=%d (%s)", rc2, kErrName(rc2));
+        rc = rc ? rc : rc2;
+    }
+
+    printf("* Mapping tests done.\n");
+    return rc;
+}
+
+
+/**
+ * Performs basic module loader tests on the specified file.
+ */
+static int BasicTests(const char *pszFilename)
+{
+    PKLDRMOD pMod;
+    int rc, rc2;
+
+    printf("tstLdrMod: Testing '%s'", pszFilename);
+    rc = kLdrModOpen(pszFilename, &pMod);
+    if (!rc)
+    {
+        rc = BasicTestsSub(pMod);
+        if (!rc)
+            rc = BasicTestsSubMap(pMod);
+        if (!rc)
+            rc = BasicTestsSub2(pMod, NULL);
+        rc2 = kLdrModClose(pMod);
+        if (rc2)
+            Failure("failed to close '%s', rc=%d (%s)", pszFilename, rc, kErrName(rc));
+        if (rc2 && !rc)
+            rc = rc2;
+    }
+    else
+        Failure("Failed to open '%s', rc=%d (%s)", pszFilename, rc, kErrName(rc));
+    return rc ? 1 : 0;
+}
+
+
+int main(int argc, char **argv)
+{
+    BasicTests(argv[argc-1]);
+
+    if (!g_cErrors)
+        printf("tstLdrMod: SUCCESS\n");
+    else
+        printf("tstLdrMod: FAILURE - %d errors\n", g_cErrors);
+    return !!g_cErrors;
+}
+
Index: /trunk/kProfiler2/Makefile.kmk
===================================================================
--- /trunk/kProfiler2/Makefile.kmk	(revision 2)
+++ /trunk/kProfiler2/Makefile.kmk	(revision 2)
@@ -0,0 +1,163 @@
+# $Id$
+## @file
+# kProfiler Mark 2, sub-makefile.
+#
+
+#
+# Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+#
+# This file is part of kProfiler.
+#
+# kProfiler is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# kProfiler 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with kProfiler; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+
+DEPTH ?= ../..
+SUB_DEPTH = ..
+include $(PATH_KBUILD)/subheader.kmk
+
+#LIBRARIES  += kPrf2GC kPrf2R0
+DLLS       += kPrf2
+PROGRAMS   += kPrf2Read
+
+
+#
+# Our template.
+#
+TEMPLATE_kPrf2 = kProfiler Template
+TEMPLATE_kPrf2_TOOL             = GCC3
+TEMPLATE_kPrf2_TOOL.os2         = GCC3OMF
+TEMPLATE_kPrf2_TOOL.win.x86     = VCC70
+TEMPLATE_kPrf2_TOOL.win.amd64   = VCC80AMD64
+TEMPLATE_kPrf2_ASTOOL           = YASM
+TEMPLATE_kPrf2_ASTOOL.os2       = NASM
+
+TEMPLATE_kPrf2_SDKS.win         = WINPSDK
+
+TEMPLATE_kPrf2_DEFS.freebsd     = KPRF_OS_FREEBSD
+TEMPLATE_kPrf2_DEFS.linux       = KPRF_OS_LINUX
+TEMPLATE_kPrf2_DEFS.os2         = KPRF_OS_OS2
+TEMPLATE_kPrf2_DEFS.win         = KPRF_OS_WINDOWS
+
+TEMPLATE_kPrf2_CXXFLAGS.freebsd = -g
+TEMPLATE_kPrf2_CXXFLAGS.linux   = -g
+TEMPLATE_kPrf2_CXXFLAGS.os2     = -g
+TEMPLATE_kPrf2_CXXFLAGS.win     = -Zi -Zl -MD -W3 -GF -GR-
+TEMPLATE_kPrf2_CXXFLAGS.win.amd64 = -GS- #-FAcs
+ifneq ($(BUILD_TYPE),debug)
+TEMPLATE_kPrf2_CXXFLAGS.freebsd+= -O3
+TEMPLATE_kPrf2_CXXFLAGS.linux  += -O3
+TEMPLATE_kPrf2_CXXFLAGS.os2    += -O3
+TEMPLATE_kPrf2_CXXFLAGS.win    += -O2xtg -Oi -Ob2
+endif
+
+TEMPLATE_kPrf2_ASFLAGS.freebsd  = -f elf
+TEMPLATE_kPrf2_ASFLAGS.linux    = -f elf
+TEMPLATE_kPrf2_ASFLAGS.os2      = -f omf
+TEMPLATE_kPrf2_ASFLAGS.win.x86  = -f win32 -g cv8
+TEMPLATE_kPrf2_ASFLAGS.win.amd64 = -f win64 -g cv8
+
+TEMPLATE_kPrf2_INCS             = \
+	../include
+
+TEMPLATE_kPrf2_LDFLAGS.freebsd  = -g
+TEMPLATE_kPrf2_LDFLAGS.linux    = -g
+TEMPLATE_kPrf2_LDFLAGS.os2      = -g
+TEMPLATE_kPrf2_LDFLAGS.win      = /DEBUG
+
+TEMPLATE_kPrf2_LIBS.freebsd     =
+TEMPLATE_kPrf2_LIBS.linux       =
+TEMPLATE_kPrf2_LIBS.os2         =
+TEMPLATE_kPrf2_LIBS.win        = \
+	$(PATH_SDK_WINPSDK_LIB)/psapi.Lib
+TEMPLATE_kPrf2_LIBS.win.x86     = \
+	$(PATH_TOOL_VCC70_LIB)/msvcrt.lib \
+	$(PATH_TOOL_VCC70_LIB)/msvcprt.lib \
+	$(PATH_TOOL_VCC70_LIB)/oldnames.lib
+
+
+#
+# kPrf2 - The profiler module.
+#
+kPrf2_TEMPLATE      = kPrf2
+kPrf2_DEFS.x86      = KPRF_BITS=32
+kPrf2_DEFS.amd64    = KPRF_BITS=64
+kPrf2_LDFLAGS.win.amd64 = -Entry:DllMain
+
+kPrf2_SOURCES       = \
+	kProfileR3.cpp
+#	kProfileGC.cpp
+#	kProfileR0.cpp
+
+kPrf2_SOURCES.win = \
+	dllmain-win.cpp \
+	prf$(BUILD_TARGET_ARCH)msc.asm \
+	kPrf2-win-$(BUILD_TARGET_ARCH).def
+prfx86msc.asm_DEFS.win.x86 = \
+	KPRF_ENTER=_KPrfEnter \
+	KPRF_LEAVE=_KPrfLeave
+prfamd64msc.asm_DEFS.win.amd64 = \
+	KPRF_ENTER=KPrfEnter \
+	KPRF_LEAVE=KPrfLeave
+
+#
+# kPrf2Read - The read & producer of statistics.
+#
+#kPrf2Read_TEMPLATE = kPrf2
+kPrf2Read_TEMPLATE = kStuffEXE
+kPrf2Read_SOURCES  = \
+	kPrf2Read.cpp
+kPrf2Read_LIBS  = \
+	$(PATH_LIB)/kDbgStatic$(SUFF_LIB) \
+	$(PATH_LIB)/kRdrStatic$(SUFF_LIB) \
+	$(PATH_LIB)/kHlpCRTStatic$(SUFF_LIB)
+
+
+#
+# A simple testcase.
+#
+PROGRAMS.win.x86 += tst
+tst_TOOL = VCC70
+tst_SDKS = WINPSDK
+tst_CFLAGS = -GH -Gh -Zi -Zl -GR- -GX- -GF- -MD -W3 -wd4244
+tst_SOURCES = tst.c
+tst.c_CFLAGS = -Od
+tst_LDFLAGS = /DEBUG
+tst_LIBS = \
+	$(PATH_TOOL_VCC70_LIB)/msvcrt.lib \
+	$(PATH_TOOL_VCC70_LIB)/msvcprt.lib \
+	$(PATH_TOOL_VCC70_LIB)/oldnames.lib \
+	$(PATH_kPrf2)/kPrf2.lib
+
+PROGRAMS += tstlongjmp
+tstlongjmp_TEMPLATE = kStuffEXE
+tstlongjmp_CFLAGS.win = -GH -Gh -Zi
+tstlongjmp_SOURCES = tstlongjmp.c
+tstlongjmp_LIBS = \
+	$(PATH_kPrf2)/kPrf2.lib
+
+# Generate the rules
+include $(PATH_KBUILD)/subfooter.kmk
+
+
+#
+# Aliases for .cpp.h files so we can more easily do syntax checking from the editor.
+#
+CORE := $(wildcard *core*.cpp.h *core*.h.h)
+$(CORE:.h=.o) $(CORE:.h=.obj) : kProfileR3.o
+
+READ := $(wildcard *read*.cpp.h *read*.h.h)
+$(READ:.h=.o) $(READ:.h=.obj) : kPrf2Read.o
+
Index: /trunk/kProfiler2/dllmain-win.cpp
===================================================================
--- /trunk/kProfiler2/dllmain-win.cpp	(revision 2)
+++ /trunk/kProfiler2/dllmain-win.cpp	(revision 2)
@@ -0,0 +1,72 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - The Windows DllMain for the profiler DLL.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfile.
+ *
+ * kProfile is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfile 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfile; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <Windows.h>
+#include "kProfileR3.h"
+
+
+/**
+ * The DLL Main for the kPrf DLL.
+ *
+ * This is required because we need to initialize the profiler at some point
+ * and because we need to know when threads terminate. (We don't care about
+ * when threads get created, we simply pick them up when we see them the
+ * first time.)
+ *
+ * @returns Success indicator.
+ * @param   hInstDll        The instance handle of the DLL. (i.e. the module handle)
+ * @param   fdwReason       The reason why we're here. This is a 'flag' for reasons of
+ *                          tradition, it's really a kind of enum.
+ * @param   pReserved       Reserved / undocumented something.
+ */
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, PVOID pReserved)
+{
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            if (kPrfInitialize())
+                return FALSE;
+            break;
+
+        case DLL_PROCESS_DETACH:
+            kPrfTerminate();
+            break;
+
+        case DLL_THREAD_ATTACH:
+            break;
+
+        case DLL_THREAD_DETACH:
+            kPrfTerminateThread();
+            break;
+    }
+
+    return TRUE;
+}
+
Index: /trunk/kProfiler2/kPrf2-win-amd64.def
===================================================================
--- /trunk/kProfiler2/kPrf2-win-amd64.def	(revision 2)
+++ /trunk/kProfiler2/kPrf2-win-amd64.def	(revision 2)
@@ -0,0 +1,33 @@
+; $Id$LIBRARY kPrf2
+;; @file
+; kProfiler Mark 2 - Windows Linker Definition File, AMD64.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+;
+; This file is part of kProfiler.
+;
+; kProfiler is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; kProfiler 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kProfiler; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+;
+
+
+LIBRARY kPrf2
+EXPORTS
+    _penter
+    _pexit
+    KPrfInit
+
+
Index: /trunk/kProfiler2/kPrf2-win-x86.def
===================================================================
--- /trunk/kProfiler2/kPrf2-win-x86.def	(revision 2)
+++ /trunk/kProfiler2/kPrf2-win-x86.def	(revision 2)
@@ -0,0 +1,32 @@
+; $Id$
+;; @file
+; kProfiler Mark 2 - Windows Linker Definition File, x86.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+;
+; This file is part of kProfiler.
+;
+; kProfiler is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; kProfiler 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kProfiler; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+;
+
+
+LIBRARY kPrf2
+EXPORTS
+    _penter
+    _pexit
+    KPrfInit
+
Index: /trunk/kProfiler2/kPrf2Read.cpp
===================================================================
--- /trunk/kProfiler2/kPrf2Read.cpp	(revision 2)
+++ /trunk/kProfiler2/kPrf2Read.cpp	(revision 2)
@@ -0,0 +1,500 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - The reader and producer of statistics.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <k/kDbg.h>
+
+
+/** @def KPRF_OFF2PTR
+ * Internal helper for converting a offset to a pointer.
+ * @internal
+ */
+#define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \
+    ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KUPTR)pHdr) )
+
+/** @def KPRF_ALIGN
+ * The usual align macro.
+ * @internal
+ */
+#define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) )
+
+/** @def KPRF_OFFSETOF
+ * My usual extended offsetof macro, except this returns KU32 and mangles the type name.
+ * @internal
+ */
+#define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member )
+
+/** @def PRF_SIZEOF
+ * Size of a kPrf type.
+ * @internal
+ */
+#define KPRF_SIZEOF(kPrfType)           sizeof(KPRF_TYPE(,kPrfType))
+
+#ifdef _MSC_VER
+# define KPRF_FMT_U64   "I64u"
+# define KPRF_FMT_X64   "I64x"
+# define KPRF_FMT_I64   "I64d"
+#else
+# define KPRF_FMT_X64   "llx"
+# define KPRF_FMT_U64   "llu"
+# define KPRF_FMT_I64   "lld"
+#endif
+
+
+/*
+ * Instantiate the readers.
+ */
+/* 32-bit */
+#define KPRF_NAME(Suffix)               KPrf32##Suffix
+#define KPRF_TYPE(Prefix,Suffix)        Prefix##KPRF32##Suffix
+#define KPRF_BITS                       32
+#define KPRF_FMT_UPTR                   "#010x"
+
+#include "prfcore.h.h"
+#include "prfreader.cpp.h"
+
+#undef KPRF_FMT_UPTR
+#undef KPRF_NAME
+#undef KPRF_TYPE
+#undef KPRF_BITS
+
+/* 64-bit */
+#define KPRF_NAME(Suffix)               KPrf64##Suffix
+#define KPRF_TYPE(Prefix,Suffix)        Prefix##KPRF64##Suffix
+#define KPRF_BITS                       64
+#ifdef _MSC_VER
+# define KPRF_FMT_UPTR                  "#018I64x"
+#else
+# define KPRF_FMT_UPTR                  "#018llx"
+#endif
+
+#include "prfcore.h.h"
+#include "prfreader.cpp.h"
+
+#undef KPRF_FMT_UPTR
+#undef KPRF_NAME
+#undef KPRF_TYPE
+#undef KPRF_BITS
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Header union type.
+ */
+typedef union KPRFHDR
+{
+    KPRF32HDR   Hdr32;
+    KPRF64HDR   Hdr64;
+} KPRFHDR;
+typedef KPRFHDR *PKPRFHDR;
+typedef const KPRFHDR *PCKPRFHDR;
+
+
+
+/**
+ * Read the data set into memory.
+ *
+ * @returns Pointer to the loaded data set. (release using free()).
+ *
+ * @param   pszFilename         The path to the profiler data set.
+ * @param   pcb                 Where to store the size of the data set.
+ * @param   pOut                Where to write errors.
+ */
+PKPRFHDR kPrfLoad(const char *pszFilename, KU32 *pcb, FILE *pOut)
+{
+    FILE *pFile = fopen(pszFilename, "rb");
+    if (!pFile)
+    {
+        fprintf(pOut, "Cannot open '%s' for reading!\n", pszFilename);
+        return NULL;
+    }
+
+    /*
+     * Read the file into memory.
+     */
+    long cbFile;
+    if (    !fseek(pFile, 0, SEEK_END)
+        &&  (cbFile = ftell(pFile)) >= 0
+        &&  !fseek(pFile, 0, SEEK_SET)
+        )
+    {
+        if (pcb)
+            *pcb = cbFile;
+
+        void *pvData = malloc(cbFile);
+        if (pvData)
+        {
+            if (fread(pvData, cbFile, 1, pFile))
+            {
+
+                fclose(pFile);
+                return (PKPRFHDR)pvData;
+            }
+            fprintf(pOut, "Failed reading '%s' into memory!\n", pszFilename);
+            free(pvData);
+        }
+        else
+            fprintf(pOut, "Failed to allocate %ld bytes of memory for reading the file '%s' into!\n", cbFile, pszFilename);
+    }
+    else
+        fprintf(pOut, "Failed to determin the size of '%s'!\n", pszFilename);
+
+    fclose(pFile);
+    return NULL;
+}
+
+
+/**
+ * Validates the data set
+ *
+ * @returns true if valid.
+ * @returns false if invalid.
+ *
+ * @param   pHdr        Pointer to the data set.
+ * @param   cb          The size of the data set.
+ * @param   pOut        Where to write error messages.
+ */
+static bool kPrfIsValidate(PCKPRFHDR pHdr, KU32 cb, FILE *pOut)
+{
+    /*
+     * We ASSUMES that the header is identicial with the exception
+     * of the uBasePtr size. (this is padded out and the upper bits are all zero)
+     */
+
+    if (    pHdr->Hdr32.u32Magic != KPRF32HDR_MAGIC
+        &&  pHdr->Hdr32.u32Magic != KPRF64HDR_MAGIC)
+    {
+        fprintf(pOut, "Invalid magic %#x\n", pHdr->Hdr32.u32Magic);
+        return false;
+    }
+
+    if (    pHdr->Hdr32.cFormatBits != 32
+        &&  pHdr->Hdr32.cFormatBits != 64)
+    {
+        fprintf(pOut, "Invalid/Unsupported bit count %u\n", pHdr->Hdr32.cFormatBits);
+        return false;
+    }
+
+    if (pHdr->Hdr32.cb > cb)
+    {
+        fprintf(pOut, "Data set size mismatch. Header say %#x, input is %#x\n", pHdr->Hdr32.cb, cb);
+        return false;
+    }
+
+#define KPRF_VALIDATE_SIZE(MemBaseName, cb32, cb64) do {\
+        if (pHdr->Hdr32.cb##MemBaseName > (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64)) \
+        { \
+            fprintf(pOut, "cb" #MemBaseName " was expected to be %#x but is %#x. Probably a format change, rebuild.\n", \
+                    (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64), pHdr->Hdr32.cb##MemBaseName); \
+            return false; \
+        }\
+    } while (0)
+
+    KPRF_VALIDATE_SIZE(Function, sizeof(KPRF32FUNC), sizeof(KPRF64FUNC));
+    KPRF_VALIDATE_SIZE(Thread, sizeof(KPRF32THREAD), sizeof(KPRF64THREAD));
+    KPRF_VALIDATE_SIZE(Stack,
+                       (KU32)&((PKPRF32STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames],
+                       (KU32)&((PKPRF64STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames]);
+
+    KUPTR cbHeader = (KUPTR)&pHdr->Hdr32.aiFunctions[pHdr->Hdr32.cFunctions] - (KUPTR)pHdr;
+    if (    cbHeader != (KU32)cbHeader
+        ||  cbHeader >= cb)
+    {
+        fprintf(pOut, "cFunctions (%#x) is too large to fit the lookup table inside the data set.\n",
+                pHdr->Hdr32.cFunctions);
+        return false;
+    }
+
+    /* The space assignment is hereby required to be equal to the member order in the header. */
+    KU32 offMin = cbHeader;
+#define KPRF_VALIDATE_OFF(off, name) do {\
+        if (    off > 0 \
+            &&  off < offMin) \
+        { \
+            fprintf(pOut, #name " (%#x) is overlapping with other element or invalid space assignment order.\n", off); \
+            return false; \
+        }\
+        if (off >= cb) \
+        { \
+            fprintf(pOut, #name " (%#x) is outside the data set (%#x)\n", off, cb); \
+            return false; \
+        }\
+    } while (0)
+#define KPRF_VALIDATE_MEM(MemBaseName) do {\
+        KPRF_VALIDATE_OFF(pHdr->Hdr32.off##MemBaseName##s, off##MemBaseName##s); \
+        if (    pHdr->Hdr32.off##MemBaseName##s \
+            &&  (   pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s > cb \
+                 || pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s < pHdr->Hdr32.off##MemBaseName##s)\
+           ) \
+        { \
+            fprintf(pOut, #MemBaseName " (%#x) is outside the data set (%#x)\n", \
+                    pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s, cb); \
+            return false; \
+        }\
+        if (pHdr->Hdr32.c##MemBaseName##s > pHdr->Hdr32.cMax##MemBaseName##s) \
+        { \
+            fprintf(pOut, "c" #MemBaseName " (%#x) higher than the max (%#x)\n", \
+                    pHdr->Hdr32.c##MemBaseName##s, pHdr->Hdr32.cMax##MemBaseName##s); \
+            return false; \
+        } \
+        if (pHdr->Hdr32.off##MemBaseName##s) \
+            offMin += pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s; \
+    } while (0)
+
+    KPRF_VALIDATE_MEM(Function);
+    KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs, offModSegs);
+    if (pHdr->Hdr32.offModSegs)
+        KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs + pHdr->Hdr32.cbMaxModSegs, cbMaxModSegs);
+    if (pHdr->Hdr32.cbModSegs > pHdr->Hdr32.cbMaxModSegs)
+    {
+        fprintf(pOut, "ccbModSegs (%#x) higher than the max (%#x)\n",
+                pHdr->Hdr32.cbModSegs, pHdr->Hdr32.cbMaxModSegs);
+        return false;
+    }
+    if (pHdr->Hdr32.offModSegs) \
+        offMin += pHdr->Hdr32.cbMaxModSegs; \
+    KPRF_VALIDATE_MEM(Thread);
+    KPRF_VALIDATE_MEM(Stack);
+    KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine, offCommandLine);
+    KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine + pHdr->Hdr32.cchCommandLine, cchCommandLine);
+
+    /*
+     * Validate the function lookup table
+     */
+    for (KU32 i = 0; i < pHdr->Hdr32.cFunctions; i++)
+        if (pHdr->Hdr32.aiFunctions[i] >= pHdr->Hdr32.cFunctions)
+        {
+            fprintf(pOut, "Function lookup entry %#x is invalid: index %#x, max is %#x\n",
+                    i, pHdr->Hdr32.aiFunctions[i], pHdr->Hdr32.cFunctions);
+            return false;
+        }
+
+    /*
+     * Validate the functions.
+     */
+    switch (pHdr->Hdr32.cFormatBits)
+    {
+        case 32:
+            return KPrf32IsValid(&pHdr->Hdr32, cb, pOut);
+
+        case 64:
+            return KPrf64IsValid(&pHdr->Hdr64, cb, pOut);
+    }
+    return false;
+#undef KPRF_VALIDATE_SIZE
+#undef KPRF_VALIDATE_MEM
+#undef KPRF_VALIDATE_OFF
+}
+
+
+/**
+ * Dumps a kProfiler 2 format file.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ *
+ * @param   pszFilename         The path to the profiler data set.
+ * @param   pOut                Where to write the output.
+ */
+int KPrfDumpFile(const char *pszFilename, FILE *pOut)
+{
+    /*
+     * Load and validate the data set.
+     */
+    KU32 cb;
+    PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut);
+    if (!pHdr)
+        return -1;
+    if (!kPrfIsValidate(pHdr, cb, pOut))
+        return -1;
+
+    /*
+     * Switch to the appropirate dumper routine.
+     */
+    int rc;
+    switch (pHdr->Hdr32.cFormatBits)
+    {
+        case 32:
+            rc = KPrf32Dump(&pHdr->Hdr32, pOut);
+            break;
+
+        case 64:
+            rc = KPrf64Dump(&pHdr->Hdr64, pOut);
+            break;
+
+        default:
+            fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits);
+            rc = -1;
+            break;
+    }
+
+    return rc;
+}
+
+
+/**
+ * Creates a HTML report from a kProfiler 2 format file.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ *
+ * @param   pszFilename         The path to the profiler data set.
+ * @param   pOut                Where to write the output.
+ */
+int KPrfHtmlReport(const char *pszFilename, FILE *pOut)
+{
+    /*
+     * Load and validate the data set.
+     */
+    KU32 cb;
+    PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut);
+    if (!pHdr)
+        return -1;
+    if (!kPrfIsValidate(pHdr, cb, pOut))
+        return -1;
+
+    /*
+     * Switch to the appropirate dumper routine.
+     */
+    int rc;
+    switch (pHdr->Hdr32.cFormatBits)
+    {
+        case 32:
+        {
+            PKPRF32REPORT pReport;
+            rc = KPrf32Analyse(&pHdr->Hdr32, &pReport);
+            if (!rc)
+            {
+                rc = KPrf32WriteHtmlReport(pReport, pOut);
+                if (rc)
+                    fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename);
+                KPrf32DeleteReport(pReport);
+            }
+            else
+                fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename);
+            break;
+        }
+
+        case 64:
+        {
+            PKPRF64REPORT pReport;
+            rc = KPrf64Analyse(&pHdr->Hdr64, &pReport);
+            if (!rc)
+            {
+                rc = KPrf64WriteHtmlReport(pReport, pOut);
+                if (rc)
+                    fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename);
+                KPrf64DeleteReport(pReport);
+            }
+            else
+                fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename);
+            break;
+        }
+
+        default:
+            fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits);
+            rc = -1;
+            break;
+    }
+
+    return rc;
+}
+
+
+
+/**
+ * Prints the usage.
+ */
+static int Usage(void)
+{
+    printf("kProfiler MK2 - Reader & Producer of Statistics\n"
+           "usage: kPrf2Read [-r|-d] <file1> [[-r|-d] file2 []]\n"
+           );
+    return 1;
+}
+
+
+int main(int argc, char **argv)
+{
+    /*
+     * Parse arguments.
+     */
+    if (argc <= 1)
+        return Usage();
+    enum { OP_DUMP, OP_HTML } enmOp = OP_DUMP;
+    for (int i = 1; i < argc; i++)
+    {
+        if (argv[i][0] == '-')
+        {
+            switch (argv[i][1])
+            {
+                case 'h':
+                case 'H':
+                case '?':
+                case '-':
+                    return Usage();
+
+                case 'd':
+                    enmOp = OP_DUMP;
+                    break;
+
+                case 'r':
+                    enmOp = OP_HTML;
+                    break;
+
+                default:
+                    printf("Syntax error: Unknown argument '%s'\n", argv[i]);
+                    return 1;
+            }
+        }
+        else
+        {
+            int rc;
+            switch (enmOp)
+            {
+                case OP_DUMP:
+                    rc = KPrfDumpFile(argv[i], stdout);
+                    break;
+                case OP_HTML:
+                    rc = KPrfHtmlReport(argv[i], stdout);
+                    break;
+            }
+            if (rc)
+                return rc;
+        }
+    }
+
+    return 0;
+}
Index: /trunk/kProfiler2/kPrfReader.h
===================================================================
--- /trunk/kProfiler2/kPrfReader.h	(revision 2)
+++ /trunk/kProfiler2/kPrfReader.h	(revision 2)
@@ -0,0 +1,45 @@
+
+
+#include <string>
+
+typedef
+
+/**
+ * Debug info cache.
+ *
+ * An objects of this class acts a frontend to the low-level
+ * debug info readers.
+ */
+class kPrfDebugInfoCache
+{
+public:
+    kPrfDebugInfoCache(unsigned cMaxModules = ~0U);
+    ~kPrfDebugInfoCache();
+
+    /** Resolves a symbol in a specific module. */
+    int findSymbol();
+    int findLine();
+};
+
+/**
+ * Internal class which does the reader job behind the API / commandline tool.
+ */
+class kPrfReader
+{
+public:
+    kPrfReader(const char *pszDataSetPath);
+    ~kPrfReader();
+
+    /** Analyses the data set. */
+    int analyse(int fSomeOptionsIHaventFiguredOutYet);
+
+    /** Writes the analysis report as HTML. */
+    int reportAsHtml(FILE *pOut);
+
+    /** Dumps the data set in a raw fashion to the specified file stream. */
+    int dump(FILE *pOut);
+
+protected:
+    /** Pointer to the debug info cache object. */
+    kPrfDebugInfoCache *pDbgCache;
+};
Index: /trunk/kProfiler2/kProfileR3.cpp
===================================================================
--- /trunk/kProfiler2/kProfileR3.cpp	(revision 2)
+++ /trunk/kProfiler2/kProfileR3.cpp	(revision 2)
@@ -0,0 +1,1662 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - The Ring-3 Implementation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#if defined(KPRF_OS_WINDOWS)
+# include <windows.h>
+# include <psapi.h>
+# include <malloc.h>
+# if _MSC_VER >= 1400
+#  include <intrin.h>
+#  define HAVE_INTRIN
+# endif
+
+#elif defined(KPRF_OS_LINUX) || defined(KPRF_OS_FREEBSD)
+# define KPRF_USE_PTHREAD
+# include <pthread.h>
+# include <stdint.h>
+# define KPRF_USE_MMAN
+# include <sys/mman.h>
+# include <sys/fcntl.h>
+# include <unistd.h>
+# include <stdlib.h>
+# ifndef O_BINARY
+#  define O_BINARY 0
+# endif
+
+#elif defined(KPRF_OS_OS2)
+# define INCL_BASE
+# include <os2.h>
+# include <stdint.h>
+# include <sys/fmutex.h>
+
+#else
+# error "not ported to this OS..."
+#endif
+
+#include <k/kDefs.h>
+#include <k/kTypes.h>
+
+/*
+ * Instantiate the header.
+ */
+#define KPRF_NAME(Suffix)               KPrf##Suffix
+#define KPRF_TYPE(Prefix,Suffix)        Prefix##KPRF##Suffix
+#if defined(KPRF_OS_WINDOWS) || defined(KPRF_OS_OS2)
+# define KPRF_DECL_FUNC(type, name)     extern "C"  __declspec(dllexport) type __cdecl KPRF_NAME(name)
+#else
+# define KPRF_DECL_FUNC(type, name)     extern "C" type KPRF_NAME(name)
+#endif
+#if 1
+# ifdef __GNUC__
+#  define KPRF_ASSERT(expr) do { if (!(expr)) { __asm__ __volatile__("int3\n\tnop\n\t");} } while (0)
+# else
+#  define KPRF_ASSERT(expr) do { if (!(expr)) { __debugbreak(); } } while (0)
+# endif
+#else
+# define KPRF_ASSERT(expr) do { } while (0)
+#endif
+
+#include "prfcore.h.h"
+
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/** Mutex lock type. */
+#if defined(KPRF_USE_PTHREAD)
+typedef pthread_mutex_t     KPRF_TYPE(,MUTEX);
+#elif defined(KPRF_OS_WINDOWS)
+typedef CRITICAL_SECTION    KPRF_TYPE(,MUTEX);
+#elif defined(KPRF_OS_OS2)
+typedef struct _fmutex      KPRF_TYPE(,MUTEX);
+#endif
+/** Pointer to a mutex lock. */
+typedef KPRF_TYPE(,MUTEX)  *KPRF_TYPE(P,MUTEX);
+
+
+#if defined(KPRF_USE_PTHREAD)
+/** Read/Write lock type. */
+typedef pthread_rwlock_t    KPRF_TYPE(,RWLOCK);
+#elif defined(KPRF_OS_WINDOWS) || defined(KPRF_OS_OS2)
+/** Read/Write lock state. */
+typedef enum KPRF_TYPE(,RWLOCKSTATE)
+{
+    RWLOCK_STATE_UNINITIALIZED = 0,
+    RWLOCK_STATE_SHARED,
+    RWLOCK_STATE_LOCKING,
+    RWLOCK_STATE_EXCLUSIVE,
+    RWLOCK_STATE_32BIT_HACK = 0x7fffffff
+} KPRF_TYPE(,RWLOCKSTATE);
+/** Update the state. */
+#define KPRF_RWLOCK_SETSTATE(pRWLock, enmNewState) \
+    kPrfAtomicSet32((volatile KU32 *)&(pRWLock)->enmState, (KU32)(enmNewState))
+
+/** Read/Write lock type. */
+typedef struct KPRF_TYPE(,RWLOCK)
+{
+    /** This mutex serialize the access and updating of the members
+     * of this structure. */
+    KPRF_TYPE(,MUTEX)       Mutex;
+    /** The current number of readers. */
+    KU32                    cReaders;
+    /** The number of readers waiting. */
+    KU32                    cReadersWaiting;
+    /** The current number of waiting writers. */
+    KU32                    cWritersWaiting;
+# if defined(KPRF_OS_WINDOWS)
+    /** The handle of the event object on which the waiting readers block. (manual reset). */
+    HANDLE                  hevReaders;
+    /** The handle of the event object on which the waiting writers block. (manual reset). */
+    HANDLE                  hevWriters;
+# elif defined(KPRF_OS_OS2)
+    /** The handle of the event semaphore on which the waiting readers block. */
+    HEV                     hevReaders;
+    /** The handle of the event semaphore on which the waiting writers block. */
+    HEV                     hevWriters;
+# endif
+    /** The current state of the read-write lock. */
+    KPRF_TYPE(,RWLOCKSTATE) enmState;
+} KPRF_TYPE(,RWLOCK);
+#endif
+/** Pointer to a Read/Write lock. */
+typedef KPRF_TYPE(,RWLOCK) *KPRF_TYPE(P,RWLOCK);
+
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The TLS index / key. */
+#if defined(KPRF_OS_WINDOWS)
+static DWORD                g_dwThreadTLS = TLS_OUT_OF_INDEXES;
+
+#elif defined(KPRF_USE_PTHREAD)
+static pthread_key_t        g_ThreadKey = (pthread_key_t)-1;
+
+#elif defined(KPRF_OS_OS2)
+static KPRF_TYPE(P,THREAD) *g_ppThread = NULL;
+
+#else
+# error "Not ported to your OS - or you're missing the OS define(s)."
+#endif
+
+/** Pointer to the profiler header. */
+static KPRF_TYPE(P,HDR)     g_pHdr = NULL;
+#define KPRF_GET_HDR()                  g_pHdr
+
+/** Whether the profiler is enabled or not. */
+static bool                 g_fEnabled = false;
+#define KPRF_IS_ACTIVE()                g_fEnabled
+
+
+/** The mutex protecting the threads in g_pHdr. */
+static KPRF_TYPE(,MUTEX)   g_ThreadsMutex;
+
+/** The mutex protecting the module segments in g_pHdr. */
+static KPRF_TYPE(,MUTEX)   g_ModSegsMutex;
+
+/** The read-write lock protecting the functions in g_pHdr. */
+static KPRF_TYPE(,RWLOCK)  g_FunctionsRWLock;
+
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void);
+#ifdef KPRF_USE_PTHREAD
+static void kPrfPThreadKeyDtor(void *pvThread);
+#endif
+
+
+/**
+ * Gets the pointer to the profiler data for the current thread.
+ *
+ * This implementation automatically adds unknown threads.
+ *
+ * @returns Pointer to the profiler thread data.
+ * @returns NULL if we're out of thread space.
+ */
+static inline KPRF_TYPE(P,THREAD) kPrfGetThread(void)
+{
+    KPRF_TYPE(P,THREAD) pThread;
+
+/* Win32/64 */
+#if defined(KPRF_OS_WINDOWS)
+    pThread = (KPRF_TYPE(P,THREAD))TlsGetValue(g_dwThreadTLS);
+
+/* Posix Threads */
+#elif defined(KPRF_USE_PTHREAD)
+    pThread = (KPRF_TYPE(P,THREAD))pthread_getspecific(g_ThreadKey);
+
+#elif defined(KPRF_OS_OS2)
+    pThread = *g_ppThread;
+
+#else
+# error not implemented
+#endif
+    if (!pThread)
+        pThread = kPrfGetThreadAutoReg();
+    return pThread;
+}
+#define KPRF_GET_THREAD()               kPrfGetThread()
+
+
+/**
+ * The the ID of the current thread.
+ *
+ * @returns The thread id.
+ */
+static inline KUPTR kPrfGetThreadId(void)
+{
+/* Win32/64 */
+#if defined(KPRF_OS_WINDOWS)
+    KUPTR ThreadId = (KUPTR)GetCurrentThreadId();
+
+/* Posix Threads */
+#elif defined(KPRF_USE_PTHREAD)
+    KUPTR ThreadId = (KUPTR)pthread_self();
+
+#elif defined(KPRF_OS_OS2)
+    PTIB pTib;
+    PPIB pPib;
+    DosGetInfoBlocks(&pTib, &pPib);
+    ThreadId = pTib->tib_ptib2->tib2_ultid;
+
+#else
+# error not implemented
+#endif
+
+    return ThreadId;
+}
+#define KPRF_GET_THREADID()             kPrfGetThreadId()
+
+
+/**
+ * The the ID of the current process.
+ *
+ * @returns The process id.
+ */
+static inline KUPTR kPrfGetProcessId(void)
+{
+/* Win32/64 */
+#if defined(KPRF_OS_WINDOWS)
+    KUPTR ThreadId = (KUPTR)GetProcessId(GetCurrentProcess());
+
+#elif defined(KPRF_OS_OS2)
+    PTIB pTib;
+    PPIB pPib;
+    DosGetInfoBlocks(&pTib, &pPib);
+    ThreadId = pPib->pib_pid;
+
+#else
+    KUPTR ThreadId = (KUPTR)getpid();
+#endif
+
+    return ThreadId;
+}
+#define KPRF_GET_PROCESSID()            kPrfGetProcessId()
+
+
+/**
+ * Sets the pointer to the profiler data for the current thread.
+ *
+ * We require fast access to the profiler thread data, so we store
+ * it in a TLS (thread local storage) item/key where the implementation
+ * allows that.
+ *
+ * @param   pThread         The pointer to the profiler thread data for the current thread.
+ */
+static inline void kPrfSetThread(KPRF_TYPE(P,THREAD) pThread)
+{
+/* Win32/64 */
+#if defined(KPRF_OS_WINDOWS)
+    BOOL fRc = TlsSetValue(g_dwThreadTLS, pThread);
+
+/* Posix Threads */
+#elif defined(KPRF_USE_PTHREAD)
+    int rc = pthread_setspecific(g_ThreadKey, pThread);
+
+#elif defined(KPRF_OS_OS2)
+    *g_ppThread = pThread;
+
+#else
+# error not implemented
+#endif
+}
+#define KPRF_SET_THREAD(pThread)        kPrfSetThread(pThread)
+
+
+/**
+ * Get the now timestamp.
+ * This must correspond to what the assembly code are doing.
+ */
+static inline KU64 kPrfNow(void)
+{
+#if defined(HAVE_INTRIN)
+    return __rdtsc();
+# else
+    union
+    {
+        KU64 u64;
+        struct
+        {
+            KU32 u32Lo;
+            KU32 u32Hi;
+        } s;
+    } u;
+# if defined(__GNUC__)
+    __asm__ __volatile__ ("rdtsc\n\t" : "=a" (u.s.u32Lo), "=d" (u.s.u32Hi));
+# else
+    __asm
+    {
+        rdtsc
+        mov     [u.s.u32Lo], eax
+        mov     [u.s.u32Hi], edx
+    }
+
+# endif
+    return u.u64;
+#endif
+}
+#define KPRF_NOW()                      kPrfNow()
+
+
+/**
+ * Atomically set a 32-bit value.
+ */
+static inline void kPrfAtomicSet32(volatile KU32 *pu32, const KU32 u32)
+{
+#if defined(HAVE_INTRIN)
+    _InterlockedExchange((long volatile *)pu32, (const long)u32);
+
+#elif defined(__GNUC__)
+    __asm__ __volatile__("xchgl %0, %1\n\t"
+                         : "=m" (*pu32)
+                         : "r" (u32));
+
+#elif _MSC_VER
+    __asm
+    {
+        mov     edx, [pu32]
+        mov     eax, [u32]
+        xchg    [edx], eax
+    }
+
+#else
+    *pu32 = u32;
+#endif
+}
+#define KPRF_ATOMIC_SET32(a,b)          kPrfAtomicSet32(a, b)
+
+
+
+/**
+ * Atomically set a 64-bit value.
+ */
+static inline void kPrfAtomicSet64(volatile KU64 *pu64, KU64 u64)
+{
+#if defined(HAVE_INTRIN) && KPRF_BITS == 64
+    _InterlockedExchange64((KI64 *)pu64, (const KI64)u64);
+
+#elif defined(__GNUC__) && KPRF_BITS == 64
+    __asm__ __volatile__("xchgq %0, %1\n\t"
+                         : "=m" (*pu64)
+                         : "r" (u64));
+
+#elif defined(__GNUC__) && KPRF_BITS == 32
+    __asm__ __volatile__("1:\n\t"
+                         "lock; cmpxchg8b %1\n\t"
+                         "jnz 1b\n\t"
+                         : "=A" (u64),
+                           "=m" (*pu64)
+                         : "0" (*pu64),
+                           "b" ( (KU32)u64 ),
+                           "c" ( (KU32)(u64 >> 32) ));
+
+#elif _MSC_VER
+    __asm
+    {
+        mov     ebx, dword ptr [u64]
+        mov     ecx, dword ptr [u64 + 4]
+        mov     esi, pu64
+        mov     eax, dword ptr [esi]
+        mov     edx, dword ptr [esi + 4]
+    retry:
+        lock cmpxchg8b [esi]
+        jnz retry
+    }
+#else
+    *pu64 = u64;
+#endif
+}
+#define KPRF_ATOMIC_SET64(a,b)          kPrfAtomicSet64(a, b)
+
+
+/**
+ * Atomically add a 32-bit integer to another.
+ */
+static inline void kPrfAtomicAdd32(volatile KU32 *pu32, const KU32 u32)
+{
+#if defined(HAVE_INTRIN)
+    _InterlockedExchangeAdd((volatile long *)pu32, (const long)u32);
+
+#elif defined(__GNUC__)
+    __asm__ __volatile__("lock; addl %0, %1\n\t"
+                         : "=m" (*pu32)
+                         : "r" (u32));
+
+#elif _MSC_VER
+    __asm
+    {
+        mov     edx, [pu32]
+        mov     eax, dword ptr [u32]
+        lock add [edx], eax
+    }
+
+#else
+    *pu32 += u32;
+#endif
+}
+#define KPRF_ATOMIC_ADD32(a,b)          kPrfAtomicAdd32(a, b)
+#define KPRF_ATOMIC_INC32(a)            kPrfAtomicAdd32(a, 1);
+#define KPRF_ATOMIC_DEC32(a)            kPrfAtomicAdd32(a, (KU32)-1);
+
+
+/**
+ * Atomically add a 64-bit integer to another.
+ * Atomically isn't quite required, just a non-corruptive manner, assuming all updates are adds.
+ */
+static inline void kPrfAtomicAdd64(volatile KU64 *pu64, const KU64 u64)
+{
+#if defined(HAVE_INTRIN) && KPRF_BITS == 64
+    _InterlockedExchangeAdd64((volatile KI64 *)pu64, (const KI64)u64);
+
+#elif defined(__GNUC__) && KPRF_BITS == 64
+    __asm__ __volatile__("lock; addq %0, %1\n\t"
+                         : "=m" (*pu64)
+                         : "r" (u64));
+
+#elif defined(__GNUC__) && KPRF_BITS == 32
+    __asm__ __volatile__("lock; addl %0, %2\n\t"
+                         "lock; adcl %1, %3\n\t"
+                         : "=m" (*(volatile KU32 *)pu64),
+                           "=m" (*((volatile KU32 *)pu64 + 1))
+                         : "r" ((KU32)u64),
+                           "r" ((KU32)(u64 >> 32)));
+
+#elif _MSC_VER
+    __asm
+    {
+        mov     edx, [pu64]
+        mov     eax, dword ptr [u64]
+        mov     ecx, dword ptr [u64 + 4]
+        lock add [edx], eax
+        lock adc [edx + 4], ecx
+    }
+
+#else
+    *pu64 += u64;
+#endif
+}
+#define KPRF_ATOMIC_ADD64(a,b)          kPrfAtomicAdd64(a, b)
+#define KPRF_ATOMIC_INC64(a)            kPrfAtomicAdd64(a, 1);
+
+
+/**
+ * Initializes a mutex.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ * @param   pMutex      The mutex to init.
+ */
+static int kPrfMutexInit(KPRF_TYPE(P,MUTEX) pMutex)
+{
+#if defined(KPRF_USE_PTHREAD)
+    if (!pthread_mutex_init(pMutex, NULL));
+        return 0;
+    return -1;
+
+#elif defined(KPRF_OS_WINDOWS)
+    InitializeCriticalSection(pMutex);
+    return 0;
+
+#elif defined(KPRF_OS_OS2)
+    if (!_fmutex_create(pMutex, 0))
+        return 0;
+    return -1;
+#endif
+}
+
+/**
+ * Deletes a mutex.
+ *
+ * @param   pMutex      The mutex to delete.
+ */
+static void kPrfMutexDelete(KPRF_TYPE(P,MUTEX) pMutex)
+{
+#if defined(KPRF_USE_PTHREAD)
+    pthread_mutex_destroy(pMutex);
+
+#elif defined(KPRF_OS_WINDOWS)
+    DeleteCriticalSection(pMutex);
+
+#elif defined(KPRF_OS_OS2)
+    _fmutex_close(pMutex);
+#endif
+}
+
+/**
+ * Locks a mutex.
+ * @param   pMutex      The mutex lock.
+ */
+static inline void kPrfMutexAcquire(KPRF_TYPE(P,MUTEX) pMutex)
+{
+#if defined(KPRF_OS_WINDOWS)
+    EnterCriticalSection(pMutex);
+
+#elif defined(KPRF_USE_PTHREAD)
+    pthread_mutex_lock(pMutex);
+
+#elif defined(KPRF_OS_OS2)
+    fmutex_request(pMutex);
+#endif
+}
+
+
+/**
+ * Unlocks a mutex.
+ * @param   pMutex      The mutex lock.
+ */
+static inline void kPrfMutexRelease(KPRF_TYPE(P,MUTEX) pMutex)
+{
+#if defined(KPRF_OS_WINDOWS)
+    LeaveCriticalSection(pMutex);
+
+#elif defined(KPRF_USE_PTHREAD)
+    pthread_mutex_lock(pMutex);
+
+#elif defined(KPRF_OS_OS2)
+    fmutex_request(pMutex);
+#endif
+}
+
+
+#define KPRF_THREADS_LOCK()             kPrfMutexAcquire(&g_ThreadsMutex)
+#define KPRF_THREADS_UNLOCK()           kPrfMutexRelease(&g_ThreadsMutex)
+
+#define KPRF_MODSEGS_LOCK()             kPrfMutexAcquire(&g_ModSegsMutex)
+#define KPRF_MODSEGS_UNLOCK()           kPrfMutexRelease(&g_ModSegsMutex)
+
+
+/**
+ * Initializes a read-write lock.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ * @param   pRWLock     The read-write lock to initialize.
+ */
+static inline int kPrfRWLockInit(KPRF_TYPE(P,RWLOCK) pRWLock)
+{
+#if defined(KPRF_USE_PTHREAD)
+    if (!pthread_rwlock_init(pRWLock, NULL))
+        return 0;
+    return -1;
+
+#elif defined(KPRF_OS_WINDOWS) || defined(KPRF_OS_OS2)
+    if (kPrfMutexInit(&pRWLock->Mutex))
+        return -1;
+    pRWLock->cReaders = 0;
+    pRWLock->cReadersWaiting = 0;
+    pRWLock->cWritersWaiting = 0;
+    pRWLock->enmState = RWLOCK_STATE_SHARED;
+# if defined(KPRF_OS_WINDOWS)
+    pRWLock->hevReaders = CreateEvent(NULL, TRUE, TRUE, NULL);
+    pRWLock->hevWriters = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (    pRWLock->hevReaders != INVALID_HANDLE_VALUE
+        &&  pRWLock->hevWriters != INVALID_HANDLE_VALUE)
+        return 0;
+    CloseHandle(pRWLock->hevReaders);
+    CloseHandle(pRWLock->hevWriters);
+
+# elif defined(KPRF_OS_OS2)
+    APIRET rc = DosCreateEventSem(NULL, &pRWLock->hevReaders, 0, TRUE);
+    if (!rc)
+    {
+        rc = DosCreateEventSem(NULL, &pRWLock->hevWriters, 0, TRUE);
+        if (!rc)
+            return 0;
+        pRWLock->hevWriters = NULLHANDLE;
+        DosCloseEventSem(pRWLock->hevReaders);
+    }
+    pRWLock->hevReaders = NULLHANDLE;
+# endif
+
+    pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED;
+    kPrfMutexDelete(&pRWLock->Mutex);
+    return -1;
+#endif
+}
+
+
+/**
+ * Deleters a read-write lock.
+ *
+ * @param   pRWLock     The read-write lock to delete.
+ */
+static inline void kPrfRWLockDelete(KPRF_TYPE(P,RWLOCK) pRWLock)
+{
+#if defined(KPRF_USE_PTHREAD)
+    pthread_rwlock_destroy(pRWLock);
+
+#elif defined(KPRF_OS_WINDOWS) || defined(KPRF_OS_OS2)
+    if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
+        return;
+
+    pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED;
+    kPrfMutexDelete(&pRWLock->Mutex);
+    pRWLock->cReaders = 0;
+    pRWLock->cReadersWaiting = 0;
+    pRWLock->cWritersWaiting = 0;
+# if defined(KPRF_OS_WINDOWS)
+    CloseHandle(pRWLock->hevReaders);
+    pRWLock->hevReaders = INVALID_HANDLE_VALUE;
+    CloseHandle(pRWLock->hevWriters);
+    pRWLock->hevWriters = INVALID_HANDLE_VALUE;
+
+# elif defined(KPRF_OS_OS2)
+    DosCloseEventSem(pRWLock->hevReaders);
+    pRWLock->hevReaders = NULLHANDLE;
+    DosCloseEventSem(pRWLock->hevWriters);
+    pRWLock->hevWriters = NULLHANDLE;
+# endif
+#endif
+}
+
+
+/**
+ * Acquires read access to the read-write lock.
+ * @param   pRWLock     The read-write lock.
+ */
+static inline void kPrfRWLockAcquireRead(KPRF_TYPE(P,RWLOCK) pRWLock)
+{
+#if defined(KPRF_USE_PTHREAD)
+    pthread_rwlock_rdlock(pRWLock);
+
+#elif defined(KPRF_OS_WINDOWS) || defined(KPRF_OS_OS2)
+    if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
+        return;
+
+    kPrfMutexAcquire(&pRWLock->Mutex);
+    if (pRWLock->enmState == RWLOCK_STATE_SHARED)
+    {
+        KPRF_ATOMIC_INC32(&pRWLock->cReaders);
+        kPrfMutexRelease(&pRWLock->Mutex);
+        return;
+    }
+
+    for (;;)
+    {
+        /* have to wait */
+        KPRF_ATOMIC_INC32(&pRWLock->cReadersWaiting);
+# if defined(KPRF_OS_WINDOWS)
+        HANDLE hev = pRWLock->hevReaders;
+        ResetEvent(hev);
+
+# elif defined(KPRF_OS_OS2)
+        HEV    hev = pRWLock->hevReaders;
+        ULONG cIgnored;
+        DosResetEventSem(hev, &cIgnored);
+
+# endif
+        kPrfMutexRelease(&pRWLock->Mutex);
+
+# if defined(KPRF_OS_WINDOWS)
+        switch (WaitForSingleObject(hev, INFINITE))
+        {
+            case WAIT_IO_COMPLETION:
+            case WAIT_TIMEOUT:
+            case WAIT_OBJECT_0:
+                break;
+            case WAIT_ABANDONED:
+            default:
+                return;
+        }
+
+# elif defined(KPRF_OS_OS2)
+        switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT))
+        {
+            case NO_ERROR:
+            case ERROR_SEM_TIMEOUT:
+            case ERROR_TIMEOUT:
+            case ERROR_INTERRUPT:
+                break;
+            default:
+                return;
+        }
+# endif
+
+        kPrfMutexAcquire(&pRWLock->Mutex);
+        if (pRWLock->enmState == RWLOCK_STATE_SHARED)
+        {
+            KPRF_ATOMIC_INC32(&pRWLock->cReaders);
+            KPRF_ATOMIC_DEC32(&pRWLock->cReadersWaiting);
+            kPrfMutexRelease(&pRWLock->Mutex);
+            return;
+        }
+    }
+#endif
+}
+
+
+/**
+ * Releases read access to the read-write lock.
+ * @param   pRWLock     The read-write lock.
+ */
+static inline void kPrfRWLockReleaseRead(KPRF_TYPE(P,RWLOCK) pRWLock)
+{
+#if defined(KPRF_USE_PTHREAD)
+    pthread_rwlock_unlock(pRWLock);
+
+#elif defined(KPRF_OS_WINDOWS) || defined(KPRF_OS_OS2)
+    if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
+        return;
+
+    /*
+     * If we're still in the shared state, or if there
+     * are more readers out there, or if there are no
+     * waiting writers, all we have to do is decrement an leave.
+     *
+     * That's the most frequent, thing and should be fast.
+     */
+    kPrfMutexAcquire(&pRWLock->Mutex);
+    KPRF_ATOMIC_DEC32(&pRWLock->cReaders);
+    if (    pRWLock->enmState == RWLOCK_STATE_SHARED
+        ||  pRWLock->cReaders
+        ||  !pRWLock->cWritersWaiting)
+    {
+        kPrfMutexRelease(&pRWLock->Mutex);
+        return;
+    }
+
+    /*
+     * Wake up one (or more on OS/2) waiting writers.
+     */
+# if defined(KPRF_OS_WINDOWS)
+    SetEvent(pRWLock->hevWriters);
+# elif defined(KPRF_OS_OS2)
+    DosPostEvent(pRWLock->hevwriters);
+# endif
+    kPrfMutexRelease(&pRWLock->Mutex);
+
+#endif
+}
+
+
+/**
+ * Acquires write access to the read-write lock.
+ * @param   pRWLock     The read-write lock.
+ */
+static inline void kPrfRWLockAcquireWrite(KPRF_TYPE(P,RWLOCK) pRWLock)
+{
+#if defined(KPRF_USE_PTHREAD)
+    pthread_rwlock_wrlock(pRWLock);
+
+#elif defined(KPRF_OS_WINDOWS) || defined(KPRF_OS_OS2)
+    if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
+        return;
+
+    kPrfMutexAcquire(&pRWLock->Mutex);
+    if (    !pRWLock->cReaders
+        &&  (   pRWLock->enmState == RWLOCK_STATE_SHARED
+             || pRWLock->enmState == RWLOCK_STATE_LOCKING)
+        )
+    {
+        KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE);
+        kPrfMutexRelease(&pRWLock->Mutex);
+        return;
+    }
+
+    /*
+     * We'll have to wait.
+     */
+    if (pRWLock->enmState == RWLOCK_STATE_SHARED)
+        KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING);
+    KPRF_ATOMIC_INC32(&pRWLock->cWritersWaiting);
+    for (;;)
+    {
+# if defined(KPRF_OS_WINDOWS)
+        HANDLE hev = pRWLock->hevWriters;
+# elif defined(KPRF_OS_OS2)
+        HEV    hev = pRWLock->hevWriters;
+# endif
+        kPrfMutexRelease(&pRWLock->Mutex);
+# if defined(KPRF_OS_WINDOWS)
+        switch (WaitForSingleObject(hev, INFINITE))
+        {
+            case WAIT_IO_COMPLETION:
+            case WAIT_TIMEOUT:
+            case WAIT_OBJECT_0:
+                break;
+            case WAIT_ABANDONED:
+            default:
+                KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
+                return;
+        }
+
+# elif defined(KPRF_OS_OS2)
+        switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT))
+        {
+            case NO_ERROR:
+            case ERROR_SEM_TIMEOUT:
+            case ERROR_TIMEOUT:
+            case ERROR_INTERRUPT:
+                break;
+            default:
+                KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
+                return;
+        }
+        ULONG cIgnored;
+        DosResetEventSem(hev, &cIgnored);
+# endif
+
+        /*
+         * Try acquire the lock.
+         */
+        kPrfMutexAcquire(&pRWLock->Mutex);
+        if (    !pRWLock->cReaders
+            &&  (   pRWLock->enmState == RWLOCK_STATE_SHARED
+                 || pRWLock->enmState == RWLOCK_STATE_LOCKING)
+            )
+        {
+            KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE);
+            KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
+            kPrfMutexRelease(&pRWLock->Mutex);
+            return;
+        }
+    }
+#endif
+}
+
+
+/**
+ * Releases write access to the read-write lock.
+ * @param   pRWLock     The read-write lock.
+ */
+static inline void kPrfRWLockReleaseWrite(KPRF_TYPE(P,RWLOCK) pRWLock)
+{
+#if defined(KPRF_USE_PTHREAD)
+    pthread_rwlock_unlock(pRWLock);
+
+#elif defined(KPRF_OS_WINDOWS) || defined(KPRF_OS_OS2)
+    if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
+        return;
+
+    /*
+     * The common thing is that there are noone waiting.
+     * But, before that usual paranoia.
+     */
+    kPrfMutexAcquire(&pRWLock->Mutex);
+    if (pRWLock->enmState != RWLOCK_STATE_EXCLUSIVE)
+    {
+        kPrfMutexRelease(&pRWLock->Mutex);
+        return;
+    }
+    if (    !pRWLock->cReadersWaiting
+        &&  !pRWLock->cWritersWaiting)
+    {
+        KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED);
+        kPrfMutexRelease(&pRWLock->Mutex);
+        return;
+    }
+
+    /*
+     * Someone is waiting, wake them up as we change the state.
+     */
+# if defined(KPRF_OS_WINDOWS)
+    HANDLE hev = INVALID_HANDLE_VALUE;
+# elif defined(KPRF_OS_OS2)
+    HEV    hev = NULLHANDLE;
+# endif
+
+    if (pRWLock->cWritersWaiting)
+    {
+        KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING);
+        hev = pRWLock->hevWriters;
+    }
+    else
+    {
+        KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED);
+        hev = pRWLock->hevReaders;
+    }
+# if defined(KPRF_OS_WINDOWS)
+    SetEvent(hev);
+# elif defined(KPRF_OS_OS2)
+    DosPostEvent(pRWLock->hevwriters);
+# endif
+    kPrfMutexRelease(&pRWLock->Mutex);
+
+#endif
+}
+
+#define KPRF_FUNCS_WRITE_LOCK()         kPrfRWLockAcquireWrite(&g_FunctionsRWLock)
+#define KPRF_FUNCS_WRITE_UNLOCK()       kPrfRWLockReleaseWrite(&g_FunctionsRWLock)
+#define KPRF_FUNCS_READ_LOCK()          kPrfRWLockAcquireRead(&g_FunctionsRWLock)
+#define KPRF_FUNCS_READ_UNLOCK()        kPrfRWLockReleaseRead(&g_FunctionsRWLock)
+
+
+
+
+/**
+ * Finds the module segment which the address belongs to.
+ *
+ */
+static int kPrfGetModSeg(KPRF_TYPE(,UPTR) uAddress, char *pszPath, KU32 cchPath, KU32 *piSegment,
+                         KPRF_TYPE(P,UPTR) puBasePtr, KPRF_TYPE(P,UPTR) pcbSegmentMinusOne)
+{
+#if defined(KPRF_OS_WINDOWS)
+    /*
+     * Enumerate the module handles.
+     */
+    HANDLE      hProcess = GetCurrentProcess();
+    DWORD       cbNeeded = 0;
+    HMODULE     hModIgnored;
+    if (    !EnumProcessModules(hProcess, &hModIgnored, sizeof(hModIgnored), &cbNeeded)
+        &&  GetLastError() != ERROR_BUFFER_OVERFLOW) /** figure out what this actually returns */
+        cbNeeded = 256 * sizeof(HMODULE);
+
+    cbNeeded += sizeof(HMODULE) * 32;
+    HMODULE *pahModules = (HMODULE *)alloca(cbNeeded);
+    if (EnumProcessModules(hProcess, pahModules, cbNeeded, &cbNeeded))
+    {
+        const unsigned cModules = cbNeeded / sizeof(HMODULE);
+        for (unsigned i = 0; i < cModules; i++)
+        {
+            __try
+            {
+                const KUPTR uImageBase = (KUPTR)pahModules[i];
+                union
+                {
+                    KU8                *pu8;
+                    PIMAGE_DOS_HEADER   pDos;
+                    PIMAGE_NT_HEADERS   pNt;
+                    PIMAGE_NT_HEADERS32 pNt32;
+                    PIMAGE_NT_HEADERS64 pNt64;
+                    KUPTR               u;
+                } u;
+                u.u = uImageBase;
+
+                /* reject modules higher than the address. */
+                if (uAddress < u.u)
+                    continue;
+
+                /* Skip past the MZ header */
+                if (u.pDos->e_magic == IMAGE_DOS_SIGNATURE)
+                    u.pu8 += u.pDos->e_lfanew;
+
+                /* Ignore anything which isn't an NT header. */
+                if (u.pNt->Signature != IMAGE_NT_SIGNATURE)
+                    continue;
+
+                /* Extract necessary info from the optional header (comes in 32-bit and 64-bit variations, we simplify a bit). */
+                KU32                    cbImage;
+                PIMAGE_SECTION_HEADER   paSHs;
+                if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
+                {
+                    paSHs = (PIMAGE_SECTION_HEADER)(u.pNt32 + 1);
+                    cbImage = u.pNt32->OptionalHeader.SizeOfImage;
+                }
+                else if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
+                {
+                    paSHs = (PIMAGE_SECTION_HEADER)(u.pNt64 + 1);
+                    cbImage = u.pNt64->OptionalHeader.SizeOfImage;
+                }
+                else
+                    continue;
+
+                /* Is our address within the image size */
+                KUPTR uRVA = uAddress - (KUPTR)pahModules[i];
+                if (uRVA >= cbImage)
+                    continue;
+
+                /*
+                 * Iterate the section headers and figure which section we're in.
+                 * (segment == section + 1)
+                 */
+                const KU32 cSHs = u.pNt->FileHeader.NumberOfSections;
+                if (uRVA < paSHs[0].VirtualAddress)
+                {
+                    /* the implicit header section */
+                    *puBasePtr          = uImageBase;
+                    *pcbSegmentMinusOne = paSHs[0].VirtualAddress - 1;
+                    *piSegment          = 0;
+                }
+                else
+                {
+                    KU32 iSH = 0;
+                    for (;;)
+                    {
+                        if (iSH >= cSHs)
+                        {
+                            /* this shouldn't happen, but in case it does simply deal with it. */
+                            *puBasePtr          = paSHs[iSH - 1].VirtualAddress + paSHs[iSH - 1].Misc.VirtualSize + uImageBase;
+                            *pcbSegmentMinusOne = cbImage - *puBasePtr;
+                            *piSegment          = iSH + 1;
+                            break;
+                        }
+                        if (uRVA - paSHs[iSH].VirtualAddress < paSHs[iSH].Misc.VirtualSize)
+                        {
+                            *puBasePtr          = paSHs[iSH].VirtualAddress + uImageBase;
+                            *pcbSegmentMinusOne = paSHs[iSH].Misc.VirtualSize;
+                            *piSegment          = iSH + 1;
+                            break;
+                        }
+                        iSH++;
+                    }
+                }
+
+                /*
+                 * Finally, get the module name.
+                 * There are multiple ways, try them all before giving up.
+                 */
+                if (    !GetModuleFileNameEx(hProcess, pahModules[i], pszPath, cchPath)
+                    &&  !GetModuleFileName(pahModules[i], pszPath, cchPath)
+                    &&  !GetMappedFileName(hProcess, (PVOID)uAddress, pszPath, cchPath)
+                    &&  !GetModuleBaseName(hProcess, pahModules[i], pszPath, cchPath))
+                    *pszPath = '\0';
+                return 0;
+            }
+            __except (EXCEPTION_EXECUTE_HANDLER)
+            {
+            }
+        }
+    }
+
+#elif defined(KPRF_OS_OS2)
+    /*
+     * Just ask the loader.
+     */
+    ULONG   offObj = 0;
+    ULONG   iObj = 0;
+    HMODULE hmod = NULLHANDLE;
+    APIRET rc = DosQueryModFromEIP(&hmod, &iObj, cchPath, pszPath, &offObj, uAddress);
+    if (!rc)
+    {
+        *piSegment = iObj;
+        *puBasePtr = uAddress - offObj;
+        *pcbSegmentMinusOne = KPRF_ALIGN(offObj, 0x1000) - 1; /* minimum size */
+
+        /*
+         * Query the page attributes starting at the current page. The query will not enter
+         * into the next object since PAG_BASE is requested.
+         */
+        ULONG cb     = ~0UL;
+        ULONG fFlags = ~0UL;
+        uAddress &= ~(KUPTR)0xfff;
+        rc = DosQueryMem((PVOID)(uAddress, &cb, &fFlags);
+        if (!rc)
+        {
+            *pcbSegmentMinusOne = (offObj & ~(KUPTR)0xfff) + KPRF_ALIGN(cb, 0x1000) - 1;
+            if ((fFlags & PAG_BASE) && cb <= 0x1000) /* don't quite remember if PAG_BASE returns one page or not */
+            {
+                cb = ~0UL;
+                fFlags = ~0UL;
+                rc = DosQueryMem((PVOID)(uAddress + 0x1000), &cb, &fFlags);
+                if (!rc & !(fFlags & (PAG_BASE | PAG_FREE)))
+                    *pcbSegmentMinusOne += KPRF_ALIGN(cb, 0x1000);
+            }
+        }
+        return 0;
+    }
+
+#endif
+    /* The common fallback */
+    *pszPath = '\0';
+    *piSegment = 0;
+    *puBasePtr = 0;
+    *pcbSegmentMinusOne = ~(KPRF_TYPE(,UPTR))0;
+    return -1;
+}
+#define KPRF_GET_MODSEG(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne) \
+                                        kPrfGetModSeg(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne)
+
+
+
+
+/*
+ * Instantiate the implementation
+ */
+#include "prfcorepre.cpp.h"
+
+#include "prfcoremodseg.cpp.h"
+#include "prfcorefunction.cpp.h"
+#include "prfcore.cpp.h"
+#include "prfcoreinit.cpp.h"
+#include "prfcoreterm.cpp.h"
+
+#include "prfcorepost.cpp.h"
+
+
+
+
+
+/**
+ * Registers an unknown thread.
+ *
+ * @returns Pointer to the registered thread.
+ */
+static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void)
+{
+    KUPTR uStackBasePtr;
+
+#if 0
+    /** @todo I'm sure Win32 has a way of obtaining the top and bottom of the stack, OS/2 did...
+     * Some limit stuff in posix / ansi also comes to mind... */
+
+#elif defined(KPRF_OS_OS2)
+    PTIB pTib;
+    PPIB pPib;
+    DosGetInfoBlocks(&pTib, &pPib); /* never fails except if you give it bad input, thus 'Get' not 'Query'. */
+    /* I never recall which of these is the right one... */
+    uStackBasePtr = (KUPTR)pTib->tib_pstack < (KUPTR)pTib->tib_pstack_limit
+        ? (KUPTR)pTib->tib_pstack
+        : (KUPTR)pTib->tib_pstack_limit;
+
+#else
+    /* the default is top of the current stack page (assuming a page to be 4KB) */
+    uStackBasePtr = (KUPTR)&uStackBasePtr;
+    uStackBasePtr = (uStackBasePtr + 0xfff) & ~(KUPTR)0xfff;
+#endif
+
+    return KPRF_NAME(RegisterThread)(uStackBasePtr, "");
+}
+
+
+/**
+ * Get a env.var. variable.
+ *
+ * @returns pszValue.
+ * @param   pszVar      The variable name.
+ * @param   pszValue    Where to store the value.
+ * @param   cchValue    The size of the value buffer.
+ * @param   pszDefault  The default value.
+ */
+static char *kPrfGetEnvString(const char *pszVar, char *pszValue, KU32 cchValue, const char *pszDefault)
+{
+#if defined(KPRF_OS_WINDOWS)
+    if (GetEnvironmentVariable(pszVar, pszValue, cchValue))
+        return pszValue;
+
+#elif defined(KPRF_OS_OS2)
+    PSZ pszValue;
+    if (    !DosScanEnv((PCSZ)pszVar, &pszValue)
+        &&  !*pszValue)
+        pszDefault = pszValue;
+
+#else
+    const char *pszTmp = getenv(pszVar);
+    if (pszTmp)
+        pszDefault = pszTmp;
+
+#endif
+
+    /*
+     * Copy the result into the buffer.
+     */
+    char *psz = pszValue;
+    while (*pszDefault && cchValue-- > 1)
+        *psz++ = *pszDefault++;
+    *psz = '\0';
+
+    return pszValue;
+}
+
+
+/**
+ * The the value of an env.var.
+ *
+ * @returns The value of the env.var.
+ * @returns The default if the value was not found.
+ * @param   pszVar      The variable name.
+ * @param   uDefault    The default value.
+ */
+static KU32 kPrfGetEnvValue(const char *pszVar, KU32 uDefault)
+{
+#if defined(KPRF_OS_WINDOWS)
+    char szBuf[128];
+    const char *pszValue = szBuf;
+    if (!GetEnvironmentVariable(pszVar, szBuf, sizeof(szBuf)))
+        pszValue = NULL;
+
+#elif defined(KPRF_OS_OS2)
+    PSZ pszValue;
+    if (DosScanEnv((PCSZ)pszVar, &pszValue))
+        pszValue = NULL;
+
+#else
+    const char *pszValue = getenv(pszVar);
+
+#endif
+
+    /*
+     * Discard the obvious stuff.
+     */
+    if (!pszValue)
+        return uDefault;
+    while (*pszValue == ' ' || *pszValue == '\t')
+        pszValue++;
+    if (!*pszValue)
+        return uDefault;
+
+    /*
+     * Interpret the value.
+     */
+    unsigned    uBase = 10;
+    KU32        uValue = 0;
+    const char *psz = pszValue;
+
+    /* prefix - only hex */
+    if (*psz == '0' && (psz[1] == 'x' || psz[1] == 'X'))
+    {
+        uBase = 16;
+        psz += 2;
+    }
+
+    /* read the value */
+    while (*psz)
+    {
+        unsigned char ch = (unsigned char)*psz;
+        if (ch >= '0' && ch <= '9')
+            ch -= '0';
+        else if (   uBase > 10
+                 && ch >= 'a' && ch <= 'f')
+            ch -= 'a' + 10;
+        else if (   uBase > 10
+                 && ch >= 'a' && ch <= 'F')
+            ch -= 'a' + 10;
+        else
+            break;
+        uValue *= uBase;
+        uValue += ch;
+        psz++;
+    }
+
+    /* postfixes */
+    switch (*psz)
+    {
+        case 'm':
+        case 'M':
+            uValue *= 1024*1024;
+            break;
+
+        case 'k':
+        case 'K':
+            uValue *= 1024;
+            break;
+    }
+
+    /*
+     * If the value is still 0, we return the default.
+     */
+    return uValue ? uValue : uDefault;
+}
+
+
+/**
+ * Allocates memory.
+ *
+ * @returns Pointer to the allocated memory.
+ * @returns NULL on failure.
+ * @param   cb      The amount of memory (in bytes) to allocate.
+ */
+static void *kPrfAllocMem(KU32 cb)
+{
+#if defined(KPRF_OS_WINDOWS)
+    void *pv = VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+
+#elif defined(KPRF_USE_MMAN)
+    void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+#elif defined(KPRF_OS_OS2)
+    void *pv;
+# ifdef INCL_DOSEXAPIS
+    if (DosAllocMemEx(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_FORK))s
+# else
+    if (DosAllocMem(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT))
+# endif
+        pvBuf = NULL;
+
+#else
+# error not implemented
+#endif
+    return pv;
+}
+
+
+/**
+ * Frees memory.
+ *
+ * @param   pv      The memory to free.
+ */
+static void kPrfFreeMem(void *pv)
+{
+#if defined(KPRF_OS_WINDOWS)
+    VirtualFree(pv, 0, MEM_RELEASE);
+
+#elif defined(KPRF_USE_MMAN)
+    munmap(pv, 0); /** @todo check if 0 is allowed here.. */
+
+#elif defined(KPRF_OS_OS2)
+# ifdef INCL_DOSEXAPIS
+    DosFreeMemEx(&pv);
+# else
+    DosFreeMem(&pv);
+# endif
+
+#else
+# error not implemented
+#endif
+}
+
+
+/**
+ * Writes a data buffer to a new file.
+ *
+ * Any existing file will be overwritten.
+ *
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ *
+ * @param   pszName     The name of the file.
+ * @param   pvData      The data to write.
+ * @param   cbData      The amount of data to write.
+ */
+static int kPrfWriteFile(const char *pszName, const void *pvData, KU32 cbData)
+{
+#if defined(KPRF_OS_WINDOWS)
+    int rc = -1;
+    HANDLE hFile = CreateFile(pszName,GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                              CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        DWORD dwWritten;
+        if (    WriteFile(hFile, pvData, cbData, &dwWritten, NULL)
+            &&  dwWritten == cbData)
+            rc = 0;
+        CloseHandle(hFile);
+    }
+    return rc;
+
+#elif defined(KPRF_OS_OS2)
+    HFILE hFile;
+    ULONG ulAction = 0;
+    APIRET rc = DosOpen(pszName, &hFile, &ulAction, cbData, FILE_NORMAL,
+                        OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
+                        OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE | OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_SEQUENTIAL,
+                        NULL);
+    if (!rc)
+    {
+        ULONG cbWritten;
+        rc = DosWrite(hFile, pvData, cbData, &cbWritten);
+        if (!rc && cbWritten != cbData)
+            rc = -1;
+        DosClose(hFile);
+    }
+    return rc ? -1 : 0;
+
+#else
+    int rc = -1;
+    int fd = open(pszName, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, 0666);
+    if (fd >= 0)
+    {
+        if (write(fd, pvData, cbData) == cbData)
+            rc = 0;
+        close(fd);
+    }
+    return rc;
+
+#endif
+}
+
+
+
+/**
+ * Initializes and start the profiling.
+ *
+ * This should typically be called from some kind of module init
+ * function, so we can start profiling upon/before entering main().
+ *
+ * @returns 0 on success
+ * @returns -1 on failure.
+ *
+ */
+int kPrfInitialize(void)
+{
+    /*
+     * Only initialize once.
+     */
+    if (KPRF_GET_HDR())
+        return 0;
+
+    /*
+     * Initial suggestions.
+     */
+    KU32    cbModSegs  = kPrfGetEnvValue("KPRF2_CBMODSEGS",  128*1024);
+    KU32    cFunctions = kPrfGetEnvValue("KPRF2_CFUNCTIONS", 8192);
+    KU32    cThreads   = kPrfGetEnvValue("KPRF2_CTHREADS",   256);
+    KU32    cStacks    = kPrfGetEnvValue("KPRF2_CSTACKS",    48);
+    KU32    cFrames    = kPrfGetEnvValue("KPRF2_CFRAMES",    448);
+    KU32    fAffinity  = kPrfGetEnvValue("KPRF2_AFFINITY",   0);
+
+    KU32    cb = KPRF_NAME(CalcSize)(cFunctions, cbModSegs, cThreads, cStacks, cFrames);
+
+    /*
+     * Allocate and initialize the data set.
+     */
+    void *pvBuf = kPrfAllocMem(cb);
+    if (!pvBuf)
+        return -1;
+
+    KPRF_TYPE(P,HDR) pHdr = KPRF_NAME(Init)(pvBuf, cb, cFunctions, cbModSegs, cThreads, cStacks, cFrames);
+    if (pHdr)
+    {
+        /*
+         * Initialize semaphores.
+         */
+        if (!kPrfMutexInit(&g_ThreadsMutex))
+        {
+            if (!kPrfMutexInit(&g_ModSegsMutex))
+            {
+                if (!kPrfRWLockInit(&g_FunctionsRWLock))
+                {
+                    /*
+                     * Allocate the TLS entry.
+                     */
+#if defined(KPRF_OS_WINDOWS)
+                    g_dwThreadTLS = TlsAlloc();
+                    if (g_dwThreadTLS != TLS_OUT_OF_INDEXES)
+
+#elif defined(KPRF_USE_PTHREAD)
+                    int rc = pthread_key_create(&g_ThreadKey, kPrfPThreadKeyDtor);
+                    if (!rc)
+
+#elif defined(KPRF_OS_OS2)
+                    int rc = DosAllocThreadLocalMemory(sizeof(void *), (PULONG*)&g_ppThread); /** @todo check if this is a count or a size. */
+                    if (!rc)
+
+#endif
+                    {
+                        /*
+                         * Apply the affinity mask, if specified.
+                         */
+                        if (fAffinity)
+                        {
+#if defined(KPRF_OS_WINDOWS)
+                            SetProcessAffinityMask(GetCurrentProcess(), fAffinity);
+#endif
+                        }
+
+                        g_pHdr = pHdr;
+                        g_fEnabled = true;
+                        return 0;
+                    }
+                    kPrfRWLockDelete(&g_FunctionsRWLock);
+                }
+                kPrfMutexDelete(&g_ModSegsMutex);
+            }
+            kPrfMutexDelete(&g_ThreadsMutex);
+        }
+    }
+    kPrfFreeMem(pvBuf);
+    return -1;
+}
+
+
+/**
+ * Stops, dumps, and terminates the profiling.
+ *
+ * This should typically be called from some kind of module destruction
+ * function, so we can profile parts of the termination sequence too.
+ *
+ * @returns 0 on success
+ * @returns -1 on failure.
+ *
+ */
+int kPrfTerminate(void)
+{
+    /*
+     * Stop the profiling.
+     * As a safety precaution, sleep a little bit to allow threads
+     * still at large inside profiler code some time to get out.
+     */
+    g_fEnabled = false;
+    KPRF_TYPE(P,HDR) pHdr = g_pHdr;
+    g_pHdr = NULL;
+    if (!pHdr)
+        return -1;
+
+#if defined(KPRF_OS_WINDOWS)
+    Sleep(10);
+#elif defined(KPRF_OS_OS2)
+    DosSleep(10);
+#else
+    usleep(10000);
+#endif
+
+    /*
+     * Unwind all active threads and so forth.
+     */
+    KPRF_NAME(TerminateAll)(pHdr);
+
+    /*
+     * Use the stack space to fill in process details.
+     */
+#if defined(KPRF_OS_WINDOWS)
+    /* all is one single string */
+    const char *pszCommandLine = GetCommandLine();
+    if (pszCommandLine)
+        KPRF_NAME(SetCommandLine)(pHdr, 1, &pszCommandLine);
+
+#elif defined(KPRF_OS_OS2) || defined(KPRF_OS_OS2)
+    PTIB pTib;
+    PPIB pPib;
+    DosGetInfoBlocks(&pTib, &pPib);
+    if (pPib->pib_pchcmd)
+    {
+        /* Tradition say that the commandline is made up of two zero terminate strings
+         * - first the executable name, then the arguments. Similar to what unix does,
+         *   only completely mocked up because of the CMD.EXE tradition.
+         */
+        const char *apszArgs[2];
+        apszArgs[0] = pPib->pib_pchcmd;
+        apszArgs[1] = pPib->pib_pchcmd;
+        while (apszArgs[1][0])
+            apszArgs[1]++;
+        apszArgs[1]++;
+        KPRF_NAME(SetCommandLine)(pHdr, 2, apszArgs);
+    }
+
+#else
+    /* linux can read /proc/self/something I guess. Don't know about the rest... */
+
+#endif
+
+    /*
+     * Write the file to disk.
+     */
+    char szName[260 + 16];
+    kPrfGetEnvString("KPRF2_FILE", szName, sizeof(szName) - 16, "kPrf2-");
+
+    /* append the process id */
+    KUPTR pid = kPrfGetProcessId();
+    char *psz = szName;
+    while (*psz)
+        psz++;
+
+    static char s_szDigits[0x11] = "0123456789abcdef";
+    KU32 uShift = KPRF_BITS - 4;
+    while (     uShift > 0
+           &&   !(pid & (0xf << uShift)))
+        uShift -= 4;
+    *psz++ = s_szDigits[(pid >> uShift) & 0xf];
+     while (uShift > 0)
+     {
+         uShift -= 4;
+         *psz++ = s_szDigits[(pid >> uShift) & 0xf];
+     }
+
+    /* .kPrf2 */
+    *psz++ = '.';
+    *psz++ = 'k';
+    *psz++ = 'P';
+    *psz++ = 'r';
+    *psz++ = 'f';
+    *psz++ = '2';
+    *psz++ = '\0';
+
+    /* write the file. */
+    int rc = kPrfWriteFile(szName, pHdr, pHdr->cb);
+
+    /*
+     * Free resources.
+     */
+    kPrfFreeMem(pHdr);
+#if defined(KPRF_OS_WINDOWS)
+    TlsFree(g_dwThreadTLS);
+    g_dwThreadTLS = TLS_OUT_OF_INDEXES;
+
+#elif defined(KPRF_USE_PTHREAD)
+    pthread_key_delete(g_ThreadKey);
+    g_ThreadKey = (pthread_key_t)-1;
+
+#elif defined(KPRF_OS_OS2)
+    DosFreeThreadLocalMemory((PULONG)g_ppThread);
+    g_ppThread = NULL;
+
+#else
+# error "port me!"
+#endif
+
+    kPrfMutexDelete(&g_ThreadsMutex);
+    kPrfMutexDelete(&g_ModSegsMutex);
+    kPrfRWLockDelete(&g_FunctionsRWLock);
+
+    return rc;
+}
+
+
+/**
+ * Terminate the current thread.
+ */
+void kPrfTerminateThread(void)
+{
+    KPRF_NAME(DeregisterThread)();
+}
+
+
+#ifdef KPRF_USE_PTHREAD
+/**
+ * TLS destructor.
+ */
+static void kPrfPThreadKeyDtor(void *pvThread)
+{
+    KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR();
+    if (pHdr)
+    {
+        KPRF_TYPE(P,THREAD) pThread = (KPRF_TYPE(P,THREAD))pvThread;
+        pthread_setspecific(g_ThreadKey, pvThread);
+        KPRF_NAME(TerminateThread)(pHdr, pThread, KPRF_NOW());
+        pthread_setspecific(g_ThreadKey, NULL);
+    }
+}
+#endif
+
Index: /trunk/kProfiler2/kProfileR3.h
===================================================================
--- /trunk/kProfiler2/kProfileR3.h	(revision 2)
+++ /trunk/kProfiler2/kProfileR3.h	(revision 2)
@@ -0,0 +1,35 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Internal header, Ring-3.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___kProfileR3_h___
+#define ___kProfileR3_h___
+
+int kPrfInitialize(void);
+int kPrfTerminate(void);
+void kPrfTerminateThread(void);
+
+#endif
+
Index: /trunk/kProfiler2/prfamd64msc.asm
===================================================================
--- /trunk/kProfiler2/prfamd64msc.asm	(revision 2)
+++ /trunk/kProfiler2/prfamd64msc.asm	(revision 2)
@@ -0,0 +1,470 @@
+; $Id$;
+;; @file
+; kProfiler Mark 2 - Microsoft C/C++ Compiler Interaction, AMD64.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+;
+; This file is part of kProfiler.
+;
+; kProfiler is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; kProfiler 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kProfiler; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+;
+
+
+[section .data]
+;
+g_fCalibrated:
+        dd 0
+g_OverheadAdj:
+        dd 0
+
+[section .text]
+
+extern KPRF_ENTER
+extern KPRF_LEAVE
+
+global _penter
+global _pexit
+
+;ifdef  UNDEFINED
+global common_return_path
+global common_overhead
+global common_no_overhead
+global calibrate
+global calib_inner_update_minimum
+global calib_inner_next
+global calib_outer_dec
+global calib_outer_inc
+global calib_done
+global calib_nullproc
+;endif
+
+
+;;
+; On x86 the call to this function has been observed to be put before
+; creating the stack frame, as the very first instruction in the function.
+;
+; Thus the stack layout is as follows:
+;       24      return address of the calling function.
+;       20      our return address - the address of the calling function + 5.
+;       1c      eax
+;       18      edx
+;       14      eflags
+;       10      ecx
+;       c       tsc high       - param 3
+;       8       tsc low
+;       4       frame pointer  - param 2
+;       0       function ptr   - param 1
+;
+;
+align 16
+_penter:
+        ; save volatile register and get the time stamp.
+        push    rax
+        push    rdx
+        rdtsc
+        pushfq
+        push    rcx
+        push    r8
+        push    r9
+        push    r10
+        push    r11
+        sub     rsp, 28h                ; rsp is unaligned at this point (8 pushes).
+                                        ; reserve 20h for spill, and 8 bytes for ts.
+
+        ; setting up the enter call frame
+        mov     r8d, edx
+        shl     r8, 32
+        or      r8, rax                 ; param 3 - the timestamp
+        mov     [rsp + 20h], r8         ; save the tsc for later use.
+        lea     rdx, [rsp + 8*8 + 28h]  ; Param 2 - default frame pointer
+        mov     rcx, [rdx]              ; Param 1 - The function address
+
+        ; MSC seems to put the _penter both before and after the typical sub rsp, xxh
+        ; statement as if it cannot quite make up its mind. We'll try adjust for this
+        ; to make the unwinding a bit more accurate wrt to longjmp/throw. But since
+        ; there are also an uneven amount of push/pop around the _penter/_pexit we
+        ; can never really make a perfect job of it. sigh.
+        cmp     word [rcx - 5 - 4], 08348h  ; sub rsp, imm8
+        jne     .not_byte_sub
+        cmp     byte [rcx - 5 - 2], 0ech
+        jne     .not_byte_sub
+        movzx   eax, byte [rcx - 5 - 1]     ; imm8
+        add     rdx, rax
+        jmp     .call_prf_enter
+.not_byte_sub:
+        cmp     word [rcx - 5 - 7], 08148h  ; sub rsp, imm8
+        jne     .not_dword_sub
+        cmp     byte [rcx - 5 - 5], 0ech
+        jne     .not_dword_sub
+        mov     eax, [rcx - 5 - 4]          ; imm32
+        add     rdx, rax
+;        jmp     .call_prf_enter
+.not_dword_sub:
+.call_prf_enter:
+        call    KPRF_ENTER
+        jmp     common_return_path
+
+
+;;
+; On x86 the call to this function has been observed to be put right before
+; return instruction. This fact matters since since we have to calc the same
+; stack address as in _penter.
+;
+; Thus the stack layout is as follows:
+;       24      return address of the calling function.
+;       20      our return address - the address of the calling function + 5.
+;       1c      eax
+;       18      edx
+;       14      eflags
+;       10      ecx
+;       c       tsc high       - param 3
+;       8       tsc low
+;       4       frame pointer  - param 2
+;       0       function ptr   - param 1
+;
+;
+align 16
+_pexit:
+        ; save volatile register and get the time stamp.
+        push    rax
+        push    rdx
+        rdtsc
+        pushfq
+        push    rcx
+        push    r8
+        push    r9
+        push    r10
+        push    r11
+        sub     rsp, 28h                ; rsp is unaligned at this point (8 pushes).
+                                        ; reserve 20h for spill, and 8 bytes for ts.
+
+        ; setting up the enter call frame
+        mov     r8d, edx
+        shl     r8, 32
+        or      r8, rax                 ; param 3 - the timestamp
+        mov     [rsp + 20h], r8         ; save the tsc for later use.
+        lea     rdx, [rsp + 8*8 + 28h]  ; Param 2 - frame pointer.
+        mov     rcx, [rdx]              ; Param 1 - The function address
+
+        ; MSC some times put the _pexit before the add rsp, xxh. To try match up with
+        ; any adjustments made in _penter, we'll try detect this.
+        cmp     word [rcx], 08348h      ; add rsp, imm8
+        jne     .not_byte_sub
+        cmp     byte [rcx + 2], 0c4h
+        jne     .not_byte_sub
+        movzx   eax, byte [rcx + 3]     ; imm8
+        add     rdx, rax
+        jmp     .call_prf_leave
+.not_byte_sub:
+        cmp     word [rcx], 08148h      ; add rsp, imm32
+        jne     .not_dword_sub
+        cmp     byte [rcx + 2], 0c4h
+        jne     .not_dword_sub
+        mov     eax, [rcx + 3]          ; imm32
+        add     rdx, rax
+;        jmp     .call_prf_leave
+.not_dword_sub:
+.call_prf_leave:
+        call    KPRF_LEAVE
+        jmp common_return_path
+
+
+;;
+; This is the common return path for both the enter and exit hooks.
+; It's kept common because we can then use the same overhead adjustment
+; and save some calibration efforts. It also saves space :-)
+align 16
+common_return_path:
+        ; Update overhead
+        test    rax, rax
+        jz      common_no_overhead
+        cmp     byte [g_fCalibrated wrt rip], 0
+        jnz     common_overhead
+        call    calibrate
+common_overhead:
+        mov     rcx, rax                ; rcx <- pointer to overhead counter.
+        mov     eax, [g_OverheadAdj wrt rip]; apply the adjustment before reading tsc
+        sub     [rsp + 20h], rax
+
+        rdtsc
+        shl     rdx, 32
+        or      rdx, rax                ; rdx = 64-bit timestamp
+        sub     rdx, [rsp + 20h]        ; rdx = elapsed
+        lock add [rcx], rdx             ; update counter.
+common_no_overhead:
+
+        ; restore volatile registers.
+        add     rsp, 28h
+        pop     r11
+        pop     r10
+        pop     r9
+        pop     r8
+        pop     rcx
+        popfq
+        pop     rdx
+        pop     rax
+        ret
+
+;;
+; Data rsi points to while we're calibrating.
+struc CALIBDATA
+    .Overhead   resq 1
+    .Profiled   resq 1
+    .EnterTS    resq 1
+    .Min        resq 1
+endstruc
+
+
+
+align 16
+;;
+; Do necessary calibrations.
+;
+calibrate:
+        ; prolog - save everything
+        push    rbp
+        pushfq
+        push    rax                     ; pushaq
+        push    rbx
+        push    rcx
+        push    rdx
+        push    rdi
+        push    rsi
+        push    r8
+        push    r9
+        push    r10
+        push    r11
+        push    r12
+        push    r13
+        push    r14
+        push    r15
+        mov     rbp, rsp
+
+        sub     rsp, CALIBDATA_size
+        mov     rsi, rsp                ; rsi points to the CALIBDATA
+
+        and     rsp, -16
+
+        ;
+        ; Indicate that we have finished calibrating.
+        ;
+        mov     eax, 1
+        xchg    dword [g_fCalibrated wrt rip], eax
+
+        ;
+        ; The outer loop - find the right adjustment.
+        ;
+        mov     ebx, 200h               ; loop counter.
+calib_outer_loop:
+
+        ;
+        ; The inner loop - calls the function number of times to establish a
+        ;                  good minimum value
+        ;
+        mov     ecx, 200h
+        mov     dword [rsi + CALIBDATA.Min], 0ffffffffh
+        mov     dword [rsi + CALIBDATA.Min + 4], 07fffffffh
+calib_inner_loop:
+
+        ; zero the overhead and profiled times.
+        xor     eax, eax
+        mov     [rsi + CALIBDATA.Overhead], rax
+        mov     [rsi + CALIBDATA.Profiled], rax
+        call    calib_nullproc
+
+        ; subtract the overhead
+        mov     rax, [rsi + CALIBDATA.Profiled]
+        sub     rax, [rsi + CALIBDATA.Overhead]
+
+        ; update the minimum value.
+        bt      rax, 63
+        jc near calib_outer_dec        ; if negative, just simplify and shortcut
+        cmp     rax, [rsi + CALIBDATA.Min]
+        jge     calib_inner_next
+calib_inner_update_minimum:
+        mov     [rsi + CALIBDATA.Min], rax
+calib_inner_next:
+        loop    calib_inner_loop
+
+        ; Is the minimum value acceptable?
+        test    dword [rsi + CALIBDATA.Min + 4], 80000000h
+        jnz     calib_outer_dec         ; simplify if negative.
+        cmp     dword [rsi + CALIBDATA.Min + 4], 0
+        jnz     calib_outer_inc         ; this shouldn't be possible
+        cmp     dword [rsi + CALIBDATA.Min], 1fh
+        jbe     calib_outer_dec         ; too low - 2 ticks per pair is the minimum!
+        ;cmp     dword [rsi + CALIBDATA.Min], 30h
+        ;jbe     calib_done              ; this is fine!
+        cmp     dword [rsi + CALIBDATA.Min], 70h ; - a bit weird...
+        jbe     calib_outer_next         ; do the full 200h*200h iteration
+calib_outer_inc:
+        inc     dword [g_OverheadAdj wrt rip]
+        jmp     calib_outer_next
+calib_outer_dec:
+        cmp     dword [g_OverheadAdj wrt rip], 1
+        je      calib_done
+        dec     dword [g_OverheadAdj wrt rip]
+calib_outer_next:
+        dec     ebx
+        jnz     calib_outer_loop
+calib_done:
+
+        ; epilog - restore it all.
+        mov     rsp, rbp
+        pop     r15
+        pop     r14
+        pop     r13
+        pop     r12
+        pop     r11
+        pop     r10
+        pop     r9
+        pop     r8
+        pop     rsi
+        pop     rdi
+        pop     rdx
+        pop     rcx
+        pop     rbx
+        pop     rax
+        popfq
+        pop     rbp
+        ret
+
+
+
+
+;;
+; The calibration _penter - this must be identical to the real thing except for the KPRF call.
+align 16
+calib_penter:
+        ; This part must be identical past the rdtsc.
+        push    rax
+        push    rdx
+        rdtsc
+        pushfq
+        push    rcx
+        push    r8
+        push    r9
+        push    r10
+        push    r11
+        sub     rsp, 28h                ; rsp is unaligned at this point (8 pushes).
+                                        ; reserve 20h for spill, and 8 bytes for ts.
+
+        ; store the entry / stack frame.
+        mov     r8d, edx
+        shl     r8, 32
+        or      r8, rax
+        mov     [rsp + 20h], r8
+
+        mov     [rsi + CALIBDATA.EnterTS], r8
+
+        lea     rax, [rsi + CALIBDATA.Overhead]
+        jmp     common_overhead
+
+
+;;
+; The calibration _pexit - this must be identical to the real thing except for the KPRF call.
+align 16
+calib_pexit:
+        ; This part must be identical past the rdtsc.
+        push    rax
+        push    rdx
+        rdtsc
+        pushfq
+        push    rcx
+        push    r8
+        push    r9
+        push    r10
+        push    r11
+        sub     rsp, 28h                ; rsp is unaligned at this point (8 pushes).
+                                        ; reserve 20h for spill, and 8 bytes for ts.
+
+        ; store the entry / stack frame.
+        mov     r8d, edx
+        shl     r8, 32
+        or      r8, rax
+        mov     [rsp + 20h], r8
+
+        sub     r8, [rsi + CALIBDATA.EnterTS]
+        add     [rsi + CALIBDATA.Profiled], r8
+
+        lea     rax, [rsi + CALIBDATA.EnterTS]
+        jmp     common_overhead
+
+
+;;
+; The 'function' we're profiling.
+; The general idea is that each pair should take something like 2-10 ticks.
+;
+; (Btw. If we don't use multiple pairs here, we end up with the wrong result.)
+align 16
+calib_nullproc:
+        call    calib_penter ;0
+        call    calib_pexit
+
+        call    calib_penter ;1
+        call    calib_pexit
+
+        call    calib_penter ;2
+        call    calib_pexit
+
+        call    calib_penter ;3
+        call    calib_pexit
+
+        call    calib_penter ;4
+        call    calib_pexit
+
+        call    calib_penter ;5
+        call    calib_pexit
+
+        call    calib_penter ;6
+        call    calib_pexit
+
+        call    calib_penter ;7
+        call    calib_pexit
+
+        call    calib_penter ;8
+        call    calib_pexit
+
+        call    calib_penter ;9
+        call    calib_pexit
+
+        call    calib_penter ;a
+        call    calib_pexit
+
+        call    calib_penter ;b
+        call    calib_pexit
+
+        call    calib_penter ;c
+        call    calib_pexit
+
+        call    calib_penter ;d
+        call    calib_pexit
+
+        call    calib_penter ;e
+        call    calib_pexit
+
+        call    calib_penter ;f
+        call    calib_pexit
+        ret
+
+
+;
+; Dummy stack check function.
+;
+global __chkstk
+__chkstk:
+    ret
Index: /trunk/kProfiler2/prfcore.cpp.h
===================================================================
--- /trunk/kProfiler2/prfcore.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfcore.cpp.h	(revision 2)
@@ -0,0 +1,653 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/**
+ * Gets a function, create a new one if necessary.
+ */
+static KPRF_TYPE(P,FUNC) KPRF_NAME(GetFunction)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC)
+{
+    /*
+     * Perform a binary search of the function lookup table.
+     */
+    KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr);
+
+    KPRF_FUNCS_READ_LOCK();
+    KI32 iStart = 0;
+    KI32 iLast  = pHdr->cFunctions - 1;
+    KI32 i      = iLast / 2;
+    for (;;)
+    {
+        KU32 iFunction = pHdr->aiFunctions[i];
+        KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr;
+        if (!iDiff)
+        {
+            KPRF_FUNCS_READ_UNLOCK();
+            return &paFunctions[iFunction];
+        }
+        if (iLast == iStart)
+            break;
+        if (iDiff < 0)
+            iLast = i - 1;
+        else
+            iStart = i + 1;
+        if (iLast < iStart)
+            break;
+        i = iStart + (iLast - iStart) / 2;
+    }
+    KPRF_FUNCS_READ_UNLOCK();
+
+    /*
+     * It wasn't found, try add it.
+     */
+    if (pHdr->cFunctions < pHdr->cMaxFunctions)
+        return KPRF_NAME(NewFunction)(pHdr, uPC);
+    return NULL;
+}
+
+
+/**
+ * Unwind one frame.
+ */
+static KU64* KPRF_NAME(UnwindOne)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KU64 TS)
+{
+    /*
+     * Pop off the frame and update the frame below / thread.
+     */
+    KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[--pStack->cFrames];
+    KU64 *pCurOverheadTicks;
+    if (pStack->cFrames)
+    {
+        KPRF_TYPE(P,FRAME) pTopFrame = pFrame - 1;
+        pTopFrame->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks;
+        pTopFrame->SleepTicks    += pFrame->SleepTicks;
+        pTopFrame->OnTopOfStackStart = TS;
+        pTopFrame->CurOverheadTicks  = 0;
+
+        pCurOverheadTicks = &pTopFrame->CurOverheadTicks;
+    }
+    else
+    {
+        KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr);
+        pThread->ProfiledTicks  += TS - pFrame->OnStackStart - pFrame->CurOverheadTicks - pFrame->OverheadTicks - pFrame->SleepTicks;
+        pThread->OverheadTicks  += pFrame->OverheadTicks + pFrame->CurOverheadTicks;
+        pThread->SleepTicks     += pFrame->SleepTicks;
+
+        pCurOverheadTicks = &pThread->OverheadTicks;
+    }
+
+    /*
+     * Update the function (if any).
+     */
+    if (pFrame->offFunction)
+    {
+        KPRF_TYPE(P,FUNC) pFunc = KPRF_OFF2PTR(P,FUNC, pFrame->offFunction, pHdr);
+
+        /* Time on stack */
+        KU64 Ticks = TS - pFrame->OnStackStart;
+        Ticks -= pFrame->OverheadTicks + pFrame->CurOverheadTicks + pFrame->SleepTicks;
+/** @todo adjust overhead */
+KPRF_ASSERT(!(Ticks >> 63));
+        if (pFunc->OnStack.MinTicks > Ticks)
+            KPRF_ATOMIC_SET64(&pFunc->OnStack.MinTicks, Ticks);
+        if (pFunc->OnStack.MaxTicks < Ticks)
+            KPRF_ATOMIC_SET64(&pFunc->OnStack.MaxTicks, Ticks);
+        KPRF_ATOMIC_ADD64(&pFunc->OnStack.SumTicks, Ticks);
+
+        /* Time on top of stack */
+        Ticks = TS - pFrame->OnTopOfStackStart;
+        Ticks -= pFrame->CurOverheadTicks;
+        Ticks += pFrame->OnTopOfStackTicks;
+/** @todo adjust overhead */
+KPRF_ASSERT(!(Ticks >> 63));
+        if (pFunc->OnTopOfStack.MinTicks > Ticks)
+            KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MinTicks, Ticks);
+        if (pFunc->OnTopOfStack.MaxTicks < Ticks)
+            KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MaxTicks, Ticks);
+        KPRF_ATOMIC_ADD64(&pFunc->OnTopOfStack.SumTicks, Ticks);
+
+        /* calls */
+        if (pFrame->cCalls)
+            KPRF_ATOMIC_ADD64(&pFunc->cCalls, pFrame->cCalls);
+    }
+
+    return pCurOverheadTicks;
+}
+
+
+/**
+ * Unwinds the stack.
+ *
+ * On MSC+AMD64 we have to be very very careful here, because the uFramePtr cannot be trusted.
+ */
+static KU64* KPRF_NAME(UnwindInt)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, KU64 TS)
+{
+    /** @todo need to deal with alternative stacks! */
+
+    /*
+     * Pop the stack until we're down below the current frame (uFramePtr).
+     */
+    KI32 iFrame = pStack->cFrames - 1;
+    KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame];
+
+    /* the most frequent case first. */
+#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64
+    if (    uFramePtr == pFrame->uFramePtr
+        ||  (   pFrame->uFramePtr < uFramePtr
+             && iFrame > 0
+             && pFrame[-1].uFramePtr > uFramePtr))
+        return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
+#else
+    if (uFramePtr == pFrame->uFramePtr)
+        return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
+#endif
+
+    /* none?  */
+    if (pFrame->uFramePtr > uFramePtr)
+        return &pFrame->CurOverheadTicks;
+
+    /* one or more, possibly all */
+    KU64 *pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
+    pFrame--;
+    if (    iFrame > 0
+#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64
+        &&  pFrame->uFramePtr <= uFramePtr
+        &&  pFrame[-1].uFramePtr > uFramePtr)
+#else
+        &&  pFrame->uFramePtr <= uFramePtr)
+#endif
+    {
+        KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr);
+        pThread->cUnwinds++;        /* (This is the reason for what looks like a bad loop unrolling.) */
+
+        pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
+        iFrame -= 2;
+        pFrame--;
+#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64
+        while (     iFrame > 0
+               &&   pFrame->uFramePtr <= uFramePtr
+               &&   pFrame[-1].uFramePtr > uFramePtr)
+#else
+        while (     iFrame >= 0
+               &&   pFrame->uFramePtr <= uFramePtr)
+#endif
+        {
+            pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
+            iFrame--;
+            pFrame--;
+        }
+    }
+
+    return pCurOverheadTicks;
+}
+
+
+
+/**
+ * Enter function.
+ *
+ * @returns Where to account overhead.
+ * @returns NULL if profiling is inactive.
+ *
+ * @param   uPC         The program counter register. (not relative)
+ * @param   uFramePtr   The stack frame address. This must match the one passed to kPrfLeave. (not relative)
+ * @param   TS          The timestamp when we entered into the profiler.
+ *                      This must not be modified touched!
+ *
+ * @internal ?
+ */
+KPRF_DECL_FUNC(KU64 *, Enter)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS)
+{
+    /*
+     * Is profiling active ?
+     */
+    if (!KPRF_IS_ACTIVE())
+        return NULL;
+
+    /*
+     * Get the header and adjust input addresses.
+     */
+    KPRF_TYPE(P,HDR)    pHdr = KPRF_GET_HDR();
+    if (!pHdr)
+        return NULL;
+    const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr;
+    if (uBasePtr)
+    {
+        uFramePtr -= uBasePtr;
+        uPC       -= uBasePtr;
+    }
+
+    /*
+     * Get the current thread. Reject unknown, inactive (in whatever way),
+     * and thread which has performed a stack switch.
+     */
+    KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
+    if (!pThread)
+        return NULL;
+    KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState;
+    if (    enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE)
+        &&  enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED)
+        )
+        return NULL;
+    if (pThread->uStackBasePtr < uFramePtr)                                         /* ASSUMES stack direction */
+    {
+        pThread->cStackSwitchRejects++;
+        return NULL;
+    }
+    pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED);
+
+
+    /*
+     * Update the thread statistics.
+     */
+    pThread->cCalls++;
+    KPRF_TYPE(,UPTR) cbStack = pThread->uStackBasePtr - uFramePtr;                 /* ASSUMES stack direction */
+    if (pThread->cbMaxStack < cbStack)
+        pThread->cbMaxStack = cbStack;
+
+    /*
+     * Check if an longjmp or throw has taken place.
+     * This check will not work if a stack switch has taken place (can fix that later).
+     */
+    KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
+    KU32 iFrame = pStack->cFrames;
+    KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame];
+    if (    iFrame
+#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64
+        &&  0) /* don't bother her yet because of _penter/_pexit frame problems. */
+#else
+        &&  pThread->uStackBasePtr >= uFramePtr                                     /* ASSUMES stack direction */
+        &&  pFrame[-1].uFramePtr + (KPRF_BITS - 8) / 8 < uFramePtr)                 /* ASSUMES stack direction */
+#endif
+    {
+        KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS);
+        iFrame = pStack->cFrames;
+    }
+
+    /*
+     * Allocate a new stack frame.
+     */
+    if (iFrame >= pHdr->cMaxStackFrames)
+    {
+        /* overflow */
+        pThread->enmState = KPRF_TYPE(,THREADSTATE_OVERFLOWED);
+        pThread->cOverflows += enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED);
+        return &pStack->aFrames[iFrame - 1].CurOverheadTicks;
+    }
+    pStack->cFrames++;
+
+    /*
+     * Update the old top frame if any.
+     */
+    if (iFrame)
+    {
+        KPRF_TYPE(P,FRAME) pOldFrame = pFrame - 1;
+        pOldFrame->OnTopOfStackTicks += TS - pOldFrame->OnTopOfStackStart;
+        pOldFrame->cCalls++;
+    }
+
+    /*
+     * Fill in the new frame.
+     */
+    pFrame->CurOverheadTicks    = 0;
+    pFrame->OverheadTicks       = 0;
+    pFrame->SleepTicks          = 0;
+    pFrame->OnStackStart        = TS;
+    pFrame->OnTopOfStackStart   = TS;
+    pFrame->OnTopOfStackTicks   = 0;
+    pFrame->cCalls              = 0;
+    pFrame->uFramePtr           = uFramePtr;
+
+    /*
+     * Find the relevant function.
+     */
+    KPRF_TYPE(P,FUNC) pFunc = KPRF_NAME(GetFunction)(pHdr, uPC);
+    if (pFunc)
+    {
+        pFrame->offFunction = KPRF_PTR2OFF(pFunc, pHdr);
+        pFunc->cOnStack++;
+    }
+    else
+        pFrame->offFunction = 0;
+
+    /*
+     * Nearly done, We only have to reactivate the thread and account overhead.
+     * The latter is delegated to the caller.
+     */
+    pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE);
+    return &pFrame->CurOverheadTicks;
+}
+
+
+/**
+ * Leave function.
+ *
+ * @returns Where to account overhead.
+ * @returns NULL if profiling is inactive.
+ *
+ * @param   uPC         The program counter register.
+ * @param   uFramePtr   The stack frame address. This must match the one passed to kPrfEnter.
+ * @param   TS          The timestamp when we entered into the profiler.
+ *                      This must not be modified because the caller could be using it!
+ * @internal
+ */
+KPRF_DECL_FUNC(KU64 *, Leave)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS)
+{
+    /*
+     * Is profiling active ?
+     */
+    if (!KPRF_IS_ACTIVE())
+        return NULL;
+
+    /*
+     * Get the header and adjust input addresses.
+     */
+    KPRF_TYPE(P,HDR)    pHdr = KPRF_GET_HDR();
+    if (!pHdr)
+        return NULL;
+    const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr;
+    if (uBasePtr)
+    {
+        uFramePtr -= uBasePtr;
+        uPC       -= uBasePtr;
+    }
+
+    /*
+     * Get the current thread and suspend profiling of the thread until we leave this function.
+     * Also reject threads which aren't active in some way.
+     */
+    KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
+    if (!pThread)
+        return NULL;
+    KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState;
+    if (    enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE)
+        &&  enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED)
+        )
+        return NULL;
+    KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
+    if (!pStack->cFrames)
+        return NULL;
+    pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED);
+
+    /*
+     * Unwind the stack down to and including the entry indicated by uFramePtr.
+     * Leave it to the caller to update the overhead.
+     */
+    KU64 *pCurOverheadTicks = KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS);
+
+    pThread->enmState = enmThreadState;
+    return pCurOverheadTicks;
+}
+
+
+/**
+ * Register the current thread.
+ *
+ * A thread can only be profiled if it has been registered by a call to this function.
+ *
+ * @param   uPC             The program counter register.
+ * @param   uStackBasePtr   The base of the stack.
+ */
+KPRF_DECL_FUNC(KPRF_TYPE(P,THREAD), RegisterThread)(KPRF_TYPE(,UPTR) uStackBasePtr, const char *pszName)
+{
+    /*
+     * Get the header and adjust input address.
+     * (It doesn't matter whether we're active or not.)
+     */
+    KPRF_TYPE(P,HDR)    pHdr = KPRF_GET_HDR();
+    if (!pHdr)
+        return NULL;
+    const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr;
+    if (uBasePtr)
+        uStackBasePtr -= uBasePtr;
+
+
+    /*
+     * Allocate a thread and a stack.
+     */
+    KPRF_THREADS_LOCK();
+    if (pHdr->cThreads < pHdr->cMaxThreads)
+    {
+        KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pHdr->offStacks, pHdr);
+        KU32               cLeft = pHdr->cMaxStacks;
+        do
+        {
+            if (!pStack->offThread)
+            {
+                /* init the stack. */
+                pStack->cFrames   = 0;
+                pStack->offThread = pHdr->offThreads + pHdr->cbThread * pHdr->cThreads++;
+                pHdr->cStacks++;
+
+                /* init the thread */
+                KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr);
+                pThread->ThreadId       = KPRF_GET_THREADID();
+                unsigned i = 0;
+                if (pszName)
+                    while (i < sizeof(pThread->szName) - 1 && *pszName)
+                        pThread->szName[i++] = *pszName++;
+                while (i < sizeof(pThread->szName))
+                    pThread->szName[i++] = '\0';
+                pThread->enmState       = KPRF_TYPE(,THREADSTATE_SUSPENDED);
+                pThread->Reserved0      = KPRF_TYPE(,THREADSTATE_TERMINATED);
+                pThread->uStackBasePtr  = uStackBasePtr;
+                pThread->cbMaxStack     = 0;
+                pThread->cCalls         = 0;
+                pThread->cOverflows     = 0;
+                pThread->cStackSwitchRejects = 0;
+                pThread->cUnwinds       = 0;
+                pThread->ProfiledTicks  = 0;
+                pThread->OverheadTicks  = 0;
+                pThread->SleepTicks     = 0;
+                pThread->offStack       = KPRF_PTR2OFF(pStack, pHdr);
+
+
+                /* set the thread and make it active. */
+                KPRF_THREADS_UNLOCK();
+                KPRF_SET_THREAD(pThread);
+                pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE);
+                return pThread;
+            }
+
+            /* next */
+            pStack = KPRF_TYPE(P,STACK)(((KPRF_TYPE(,UPTR))pStack + pHdr->cbStack));
+        } while (--cLeft > 0);
+    }
+
+    KPRF_THREADS_UNLOCK();
+    return NULL;
+}
+
+
+/**
+ * Terminates a thread.
+ *
+ * To terminate the current thread use DeregisterThread(), because that
+ * cleans up the TLS entry too.
+ *
+ * @param   pHdr        The profiler data set header.
+ * @param   pThread     The thread to terminate.
+ * @param   TS          The timestamp to use when terminating the thread.
+ */
+KPRF_DECL_FUNC(void, TerminateThread)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,THREAD) pThread, KU64 TS)
+{
+    if (pThread->enmState == KPRF_TYPE(,THREADSTATE_TERMINATED))
+        return;
+    pThread->enmState = KPRF_TYPE(,THREADSTATE_TERMINATED);
+
+    /*
+     * Unwind the entire stack.
+     */
+    if (pThread->offStack)
+    {
+        KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
+        for (KU32 cFrames = pStack->cFrames; cFrames > 0; cFrames--)
+            KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS);
+
+        /*
+         * Free the stack.
+         */
+        pThread->offStack = 0;
+        KPRF_THREADS_LOCK();
+        pStack->offThread = 0;
+        pHdr->cStacks--;
+        KPRF_THREADS_UNLOCK();
+    }
+}
+
+
+/**
+ * Deregister (terminate) the current thread.
+ */
+KPRF_DECL_FUNC(void, DeregisterThread)(void)
+{
+    KU64 TS = KPRF_NOW();
+
+    /*
+     * Get the header, then get the thread and mark it terminated.
+     * (It doesn't matter whether we're active or not.)
+     */
+    KPRF_TYPE(P,HDR)    pHdr = KPRF_GET_HDR();
+    if (!pHdr)
+        return;
+
+    KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
+    KPRF_SET_THREAD(NULL);
+    if (!pThread)
+        return;
+    KPRF_NAME(TerminateThread)(pHdr, pThread, TS);
+}
+
+
+/**
+ * Resumes / restarts a thread.
+ *
+ * @param   fReset  If set the stack is reset.
+ */
+KPRF_DECL_FUNC(void, ResumeThread)(int fReset)
+{
+    KU64 TS = KPRF_NOW();
+
+    /*
+     * Get the header, then get the thread and mark it terminated.
+     * (It doesn't matter whether we're active or not.)
+     */
+    KPRF_TYPE(P,HDR)    pHdr = KPRF_GET_HDR();
+    if (!pHdr)
+        return;
+
+    KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
+    if (!pThread)
+        return;
+    if (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED))
+        return;
+
+    /*
+     * Reset (unwind) the stack?
+     */
+    KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
+    if (fReset)
+    {
+        KU32 cFrames = pStack->cFrames;
+        while (cFrames-- > 0)
+            KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS);
+    }
+    /*
+     * If we've got any thing on the stack, we'll have to stop the sleeping period.
+     */
+    else if (pStack->cFrames > 0)
+    {
+        KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1];
+
+        /* update the sleeping time and set the start of the new top-of-stack period. */
+        pFrame->SleepTicks += TS - pFrame->OnTopOfStackStart;
+        pFrame->OnTopOfStackStart = TS;
+    }
+    /** @todo we're not accounting overhead here! */
+
+    /*
+     * We're done, switch the thread to active state.
+     */
+    pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE);
+}
+
+
+/**
+ * Suspend / completes a thread.
+ *
+ * The thread will be in a suspend state where the time will be accounted for as sleeping.
+ *
+ * @param   fUnwind     If set the stack is unwound and the thread statistics updated.
+ */
+KPRF_DECL_FUNC(void, SuspendThread)(int fUnwind)
+{
+    KU64 TS = KPRF_NOW();
+
+    /*
+     * Get the header, then get the thread and mark it terminated.
+     * (It doesn't matter whether we're active or not.)
+     */
+    KPRF_TYPE(P,HDR)    pHdr = KPRF_GET_HDR();
+    if (!pHdr)
+        return;
+
+    KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
+    if (!pThread)
+        return;
+    if (    pThread->enmState != KPRF_TYPE(,THREADSTATE_ACTIVE)
+        &&  pThread->enmState != KPRF_TYPE(,THREADSTATE_OVERFLOWED)
+        &&  (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED) || fUnwind))
+        return;
+
+    pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED);
+
+    /*
+     * Unwind the stack?
+     */
+    KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
+    if (fUnwind)
+    {
+        KU32 cFrames = pStack->cFrames;
+        while (cFrames-- > 0)
+            KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS);
+    }
+    /*
+     * If we've got any thing on the stack, we'll have to record the sleeping period
+     * of the thread. If not we'll ignore it (for now at least).
+     */
+    else if (pStack->cFrames > 0)
+    {
+        KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1];
+
+        /* update the top of stack time and set the start of the sleep period. */
+        pFrame->OnTopOfStackTicks += TS - pFrame->OnTopOfStackStart;
+        pFrame->OnTopOfStackStart = TS;
+    }
+
+    /** @todo we're not accounting overhead here! */
+}
+
+
Index: /trunk/kProfiler2/prfcore.h.h
===================================================================
--- /trunk/kProfiler2/prfcore.h.h	(revision 2)
+++ /trunk/kProfiler2/prfcore.h.h	(revision 2)
@@ -0,0 +1,377 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core Header Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/** @def KPRF_NAME
+ * Mixed case name macro.
+ */
+#ifndef KPRF_NAME
+# define KPRF_NAME(Name)        Name
+#endif
+
+/** @def KPRF_TYPE
+ * Upper case type name macro.
+ */
+#ifndef KPRF_TYPE
+# define KPRF_TYPE(Prefix,Name) Prefix##Name
+#endif
+
+/** @type KPRF_DECL_FUNC
+ * The calling convention used.
+ */
+#ifndef KPRF_DECL_FUNC
+# define KPRF_DECL_FUNC(type, name) type name
+#endif
+
+/** @def KPRF_BITS
+ * The bitsize of the format.
+ */
+#ifndef KPRF_BITS
+# define KPRF_BITS  32
+#endif
+
+/** @type UPTR
+ * The basic unsigned interger pointer type.
+ */
+/** @type IPTR
+ * The basic signed interger pointer type.
+ */
+#if KPRF_BITS == 16
+typedef KU16    KPRF_TYPE(,UPTR);
+typedef KI16    KPRF_TYPE(,IPTR);
+#elif KPRF_BITS == 32
+typedef KU32    KPRF_TYPE(,UPTR);
+typedef KI32    KPRF_TYPE(,IPTR);
+#elif KPRF_BITS == 64
+typedef KU64    KPRF_TYPE(,UPTR);
+typedef KI64    KPRF_TYPE(,IPTR);
+#else
+# error "KPRF_BITS has an invalid value. Supported values are 16, 32 and 64."
+#endif
+/** @type KPRF_TYPE(P,UPTR)
+ * Pointer to the basic pointer type.
+ */
+typedef KPRF_TYPE(,UPTR) *KPRF_TYPE(P,UPTR);
+
+
+/**
+ * Various constants.
+ */
+enum KPRF_TYPE(,CONSTANTS)
+{
+    /** Magic for the profiler header. (Unix Epoc) */
+    KPRF_TYPE(,HDR_MAGIC) = 0x19700101
+};
+
+
+/**
+ * The profile data header.
+ */
+typedef struct KPRF_TYPE(,HDR)
+{
+    /** [0] The magic number for file data. (KPRF_TYPE(,HDR_MAGIC)) */
+    KU32                    u32Magic;
+    /** [4] KPRF_BITS. */
+    KU32                    cFormatBits;
+    /** [8] The base address which all pointers should be relative to. */
+    KPRF_TYPE(,UPTR)        uBasePtr;
+#if KPRF_BITS <= 16
+    /** [a] Reserved. */
+    KU16                    u16Reserved;
+#endif
+#if KPRF_BITS <= 32
+    /** [c] Reserved. */
+    KU32                    u32Reserved;
+#endif
+    /** [10] The size of this data set. */
+    KU32                    cb;
+    /** [10] The allocated data set size. */
+    KU32                    cbAllocated;
+
+    /** [18] The max number of functions the function table can hold. */
+    KU32                    cMaxFunctions;
+    /** [1c] The current number of functions in the function table. */
+    KU32                    cFunctions;
+    /** [20] The offset of the function table (relative to this header). */
+    KU32                    offFunctions;
+    /** [24] The size of a function entry. */
+    KU32                    cbFunction;
+
+    /** [28] The max number of bytes the module segments can occupy. */
+    KU32                    cbMaxModSegs;
+    /** [2c] The current size of the module segment records. */
+    KU32                    cbModSegs;
+    /** [30] The offset of the module segment records (relative to this header). */
+    KU32                    offModSegs;
+
+    /** [34] The max number of threads the thread table can contain. */
+    KU32                    cMaxThreads;
+    /** [38] The current number of threads in the thread table. */
+    KU32                    cThreads;
+    /** [3c] The offset of the thread table (relative to this header). */
+    KU32                    offThreads;
+    /** [40] The size of a thread entry. */
+    KU32                    cbThread;
+
+    /** [44] The max number of stacks the stack table can contain. */
+    KU32                    cMaxStacks;
+    /** [48] The max number of stacks.
+     * Unlike the other members, the stacks can be reused. It follows that
+     * this count doesn't specify the number of used slots from the start. */
+    KU32                    cStacks;
+    /** [4c] The offset of the thread table (relative to this header).
+     * This is usually 0 in a stored data set. */
+    KU32                    offStacks;
+    /** [50] The size of a stack. */
+    KU32                    cbStack;
+    /** [54] The maxium stack depth. */
+    KU32                    cMaxStackFrames;
+
+    /** [58] The process commandline.
+     * Might not always apply is will be 0 in those cases. This is normally written
+     * where the stacks used to be.
+     */
+    KU32                    offCommandLine;
+    /** [5c] The length of the command line. (excludes the terminator). */
+    KU32                    cchCommandLine;
+
+    /** [60]  The function lookup table (it contains indexes).
+     * This is sorted by address so that a binary search can be performed.
+     * Access to this table is managed externally, but generally a read/write lock is employed. */
+    KU32                    aiFunctions[1];
+} KPRF_TYPE(,HDR);
+/** Pointer to a profiler data header. */
+typedef KPRF_TYPE(,HDR) *KPRF_TYPE(P,HDR);
+/** Pointer to a const profiler data header. */
+typedef const KPRF_TYPE(,HDR) *KPRF_TYPE(PC,HDR);
+
+
+/**
+ * Time statistics.
+ */
+typedef struct KPRF_TYPE(,TIMESTAT)      /** @todo bad names and descriptions! */
+{
+    /** The minimum period */
+    KU64 volatile           MinTicks;
+    /** The maximum period */
+    KU64 volatile           MaxTicks;
+    /** The sum of all periods. */
+    KU64 volatile           SumTicks;
+} KPRF_TYPE(,TIMESTAT);
+/** Pointer to time statistics. */
+typedef KPRF_TYPE(,TIMESTAT) *KPRF_TYPE(P,TIMESTAT);
+/** Pointer to const time statistics. */
+typedef const KPRF_TYPE(,TIMESTAT) *KPRF_TYPE(PC,TIMESTAT);
+
+
+/**
+ * A Module Segment.
+ */
+typedef struct KPRF_TYPE(,MODSEG)
+{
+    /** The address of the segment. (relative address) */
+    KPRF_TYPE(,UPTR)        uBasePtr;
+    /** The size of the segment minus one (so the entire address space can be covered). */
+    KPRF_TYPE(,UPTR)        cbSegmentMinusOne;
+    /** The segment number. (0 based) */
+    KU32                    iSegment;
+    /** Flag indicating whether this segment is loaded or not.
+     * (A 16-bit value was choosen out of convenience, all that's stored is 0 or 1 anyway.) */
+    KU16                    fLoaded;
+    /** The length of the path.
+     * This is used to calculate the length of the record: offsetof(MODSEG, szPath) + cchPath + 1 */
+    KU16                    cchPath;
+    /** The module name. */
+    char                    szPath[1];
+} KPRF_TYPE(,MODSEG);
+/** Pointer to a module segment. */
+typedef KPRF_TYPE(,MODSEG) *KPRF_TYPE(P,MODSEG);
+/** Pointer to a const module segment. */
+typedef const KPRF_TYPE(,MODSEG) *KPRF_TYPE(PC,MODSEG);
+
+
+/**
+ * The profiler data for a function.
+ */
+typedef struct KPRF_TYPE(,FUNC)
+{
+    /** The entry address of the function. (relative address)
+     * This is the return address of the entry hook (_mcount, _penter, _ProfileHook32, ...). */
+    KPRF_TYPE(,UPTR)        uEntryPtr;
+    /** Offset (relative to the profiler header) of the module segment to which this function belongs. */
+    KU32                    offModSeg;
+
+    /** The number times on the stack. */
+    KU64 volatile           cOnStack;
+    /** The number of calls made from this function. */
+    KU64 volatile           cCalls;
+
+    /** Time on stack. */
+    KPRF_TYPE(,TIMESTAT)    OnStack;
+    /** Time on top of the stack, i.e. executing. */
+    KPRF_TYPE(,TIMESTAT)    OnTopOfStack;
+
+    /** @todo recursion */
+
+} KPRF_TYPE(,FUNC);
+/** Pointer to the profiler data for a function. */
+typedef KPRF_TYPE(,FUNC)       *KPRF_TYPE(P,FUNC);
+/** Pointer to the const profiler data for a function. */
+typedef const KPRF_TYPE(,FUNC) *KPRF_TYPE(PC,FUNC);
+
+
+/**
+ * Stack frame.
+ */
+typedef struct KPRF_TYPE(,FRAME)
+{
+    /** The accumulated overhead.
+     * Over head is accumulated by the parent frame when a child is poped off the stack. */
+    KU64                    OverheadTicks;
+    /** The current (top of stack) overhead. */
+    KU64                    CurOverheadTicks;
+    /** The accumulated sleep ticks.
+     * It's possible to notify the profiler that the thread is being put into a wait/sleep/yield
+     * state. The time spent sleeping is transfered to the parent frame when poping of a child one. */
+    KU64                    SleepTicks;
+    /** The start of the on-stack period. */
+    KU64                    OnStackStart;
+    /** The accumulated time on top (excludes overhead (sleep doesn't apply here obviously)). */
+    KU64                    OnTopOfStackTicks;
+    /** The start of the current on-top-of-stack period.
+     * This is also to mark the start of a sleeping period, the ResumeThread function will always
+     * treat it as the start of the suspend period. */
+    KU64                    OnTopOfStackStart;
+    /** The number of calls made from this stack frame. */
+    KU64                    cCalls;
+    /** Stack address of this frame.
+     * This is used to detect throw and longjmp, and is also used to deal with overflow. (relative address) */
+    KPRF_TYPE(,UPTR)        uFramePtr;
+    /** Offset (relative to the profiler header) to the function record.
+     * This is 0 if we're out of function space. */
+    KU32                    offFunction;
+} KPRF_TYPE(,FRAME);
+/** Pointer to a stack frame. */
+typedef KPRF_TYPE(,FRAME) *KPRF_TYPE(P,FRAME);
+/** Pointer to a const stack frame. */
+typedef const KPRF_TYPE(,FRAME) *KPRF_TYPE(PC,FRAME);
+
+
+/**
+ * Stack.
+ */
+typedef struct KPRF_TYPE(,STACK)
+{
+    /** The offset (relative to the profiler header) of the thread owning the stack.
+     * This is zero if not in use, and non-zero if in use. */
+    KU32                        offThread;
+    /** The number of active stack frames. */
+    KU32                        cFrames;
+    /** The stack frames.
+     * The actual size of this array is specified in the header. */
+    KPRF_TYPE(,FRAME)           aFrames[1];
+} KPRF_TYPE(,STACK);
+/** Pointer to a stack. */
+typedef KPRF_TYPE(,STACK) *KPRF_TYPE(P,STACK);
+/** Pointer to a const stack. */
+typedef const KPRF_TYPE(,STACK) *KPRF_TYPE(PC,STACK);
+
+
+/**
+ * The thread state.
+ */
+typedef enum KPRF_TYPE(,THREADSTATE)
+{
+    /** The thread hasn't been used yet. */
+    KPRF_TYPE(,THREADSTATE_UNUSED) = 0,
+    /** The thread is activly being profiled.
+     * A thread is added in the suspended state and then activated when
+     * starting to execute the first function.
+     */
+    KPRF_TYPE(,THREADSTATE_ACTIVE),
+    /** The thread is currently suspended from profiling.
+     * Upon entering profiler code the thread is suspended, it's reactivated
+     * upon normal return.
+     */
+    KPRF_TYPE(,THREADSTATE_SUSPENDED),
+    /** The thread is currently suspended due of stack overflow.
+     * When we overflow the stack frame array, the thread enter the overflow state. In this
+     * state nothing is profiled but we keep looking for the exit of the top frame. */
+    KPRF_TYPE(,THREADSTATE_OVERFLOWED),
+    /** The thread is terminated.
+     * When we received a thread termination notification the thread is unwinded, statistics
+     * updated and the state changed to terminated. A terminated thread cannot be revivied. */
+    KPRF_TYPE(,THREADSTATE_TERMINATED),
+
+    /** Ensure 32-bit size. */
+    KPRF_TYPE(,THREADSTATE_32BIT_HACK) = 0x7fffffff
+} KPRF_TYPE(,THREADSTATE);
+
+
+/**
+ * Thread statistics and stack.
+ */
+typedef struct KPRF_TYPE(,THREAD)
+{
+    /** The native thread id. */
+    KU64                        ThreadId;
+    /** The thread name. (optional) */
+    char                        szName[32];
+    /** The thread current thread state. */
+    KPRF_TYPE(,THREADSTATE)     enmState;
+    /** Alignment. */
+    KPRF_TYPE(,THREADSTATE)     Reserved0;
+    /** The base pointer of the thread stack. (relative address) */
+    KPRF_TYPE(,UPTR)            uStackBasePtr;
+    /** The maximum depth of the thread stack (bytes). */
+    KPRF_TYPE(,UPTR)            cbMaxStack;
+    /** The number of calls done by this thread. */
+    KU64                        cCalls;
+    /** The number of times the stack overflowed. */
+    KU64                        cOverflows;
+    /** The number of times stack entries has been rejected because of a stack switch. */
+    KU64                        cStackSwitchRejects;
+    /** The number of times the stack has been unwinded more than one frame. */
+    KU64                        cUnwinds;
+
+    /** The profiled ticks. (This does not include sleep or overhead ticks.)
+     * This is the accumulated on-stack values for the final stack frames. */
+    KU64                        ProfiledTicks;
+    /** The accumulated overhead of this thread. */
+    KU64                        OverheadTicks;
+    /** The accumulated sleep ticks for this thread.
+     * See KPRF_TYPE(,FRAME)::SleepTicks for details. */
+    KU64                        SleepTicks;
+
+    /** The offset of the stack. */
+    KU32                        offStack;
+} KPRF_TYPE(,THREAD);
+/** Pointer to a thread. */
+typedef KPRF_TYPE(,THREAD) *KPRF_TYPE(P,THREAD);
+/** Pointer to a const thread. */
+typedef const KPRF_TYPE(,THREAD) *KPRF_TYPE(PC,THREAD);
+
+
Index: /trunk/kProfiler2/prfcorefunction.cpp.h
===================================================================
--- /trunk/kProfiler2/prfcorefunction.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfcorefunction.cpp.h	(revision 2)
@@ -0,0 +1,123 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core NewFunction Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/**
+ * Creates a new function.
+ *
+ * @returns Pointer to the new function.
+ * @returns NULL if we're out of space.
+ */
+static KPRF_TYPE(P,FUNC) KPRF_NAME(NewFunction)(KPRF_TYPE(P,HDR) pHdr,KPRF_TYPE(,UPTR) uPC)
+{
+    /*
+     * First find the position of the function (it might actually have been inserted by someone else by now too).
+     */
+    KPRF_FUNCS_WRITE_LOCK();
+
+    KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr);
+    KI32 iStart = 0;
+    KI32 iLast  = pHdr->cFunctions - 1;
+    KI32 i      = iLast / 2;
+    for (;;)
+    {
+        KU32 iFunction = pHdr->aiFunctions[i];
+        KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr;
+        if (!iDiff)
+        {
+            KPRF_FUNCS_WRITE_UNLOCK();
+            return &paFunctions[iFunction];
+        }
+        if (iLast == iStart)
+            break;
+        if (iDiff < 0)
+            iLast = i - 1;
+        else
+            iStart = i + 1;
+        if (iLast < iStart)
+            break;
+        i = iStart + (iLast - iStart) / 2;
+    }
+
+    /*
+     * Adjust the index so we're exactly in the right spot.
+     * (I've too much of a headache to figure out if the above loop leaves us where we should be.)
+     */
+    const KI32 iNew = pHdr->cFunctions;
+    if (paFunctions[pHdr->aiFunctions[i]].uEntryPtr > uPC)
+    {
+        while (     i > 0
+               &&   paFunctions[pHdr->aiFunctions[i - 1]].uEntryPtr > uPC)
+            i--;
+    }
+    else
+    {
+        while (     i < iNew
+               &&   paFunctions[pHdr->aiFunctions[i]].uEntryPtr < uPC)
+            i++;
+    }
+
+    /*
+     * Ensure that there still is space for the function.
+     */
+    if (iNew >= (KI32)pHdr->cMaxFunctions)
+    {
+        KPRF_FUNCS_WRITE_UNLOCK();
+        return NULL;
+    }
+    pHdr->cFunctions++;
+    KPRF_TYPE(P,FUNC) pNew = &paFunctions[iNew];
+
+    /* init the new function entry */
+    pNew->uEntryPtr  = uPC;
+    pNew->offModSeg  = 0;
+    pNew->cOnStack   = 0;
+    pNew->cCalls     = 0;
+    pNew->OnStack.MinTicks      = ~(KU64)0;
+    pNew->OnStack.MaxTicks      = 0;
+    pNew->OnStack.SumTicks      = 0;
+    pNew->OnTopOfStack.MinTicks = ~(KU64)0;
+    pNew->OnTopOfStack.MaxTicks = 0;
+    pNew->OnTopOfStack.SumTicks = 0;
+
+    /* shift the function index array and insert the new one. */
+    KI32 j = iNew;
+    while (j > i)
+    {
+        pHdr->aiFunctions[j] = pHdr->aiFunctions[j - 1];
+        j--;
+    }
+    pHdr->aiFunctions[i] = iNew;
+    KPRF_FUNCS_WRITE_UNLOCK();
+
+    /*
+     * Record the module segment (i.e. add it if it's new).
+     */
+    pNew->offModSeg = KPRF_NAME(RecordModSeg)(pHdr, uPC);
+
+    return pNew;
+}
+
Index: /trunk/kProfiler2/prfcoreinit.cpp.h
===================================================================
--- /trunk/kProfiler2/prfcoreinit.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfcoreinit.cpp.h	(revision 2)
@@ -0,0 +1,187 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core Initialization Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/**
+ * Calculates the size of the profiler data set.
+ *
+ * @returns The size of the data set in bytes.
+ *
+ * @param   cMaxFunctions       The max number of functions.
+ * @param   cbMaxModSeg         The max bytes for module segments.
+ * @param   cMaxThreads         The max number of threads.
+ * @param   cMaxStacks          The max number of stacks. (should be less or equal to the max number of threads)
+ * @param   cMaxStackFrames     The max number of frames on each of the stacks.
+ *
+ * @remark  This function does not input checks, it only aligns it. The caller is
+ *          responsible for the input to make some sense.
+ */
+KPRF_DECL_FUNC(KU32, CalcSize)(KU32 cMaxFunctions, KU32 cbMaxModSegs, KU32 cMaxThreads, KU32 cMaxStacks, KU32 cMaxStackFrames)
+{
+    /*
+     * Normalize input.
+     */
+    KPRF_SETMIN_ALIGN(cMaxFunctions, 16, 16);
+    KPRF_SETMIN_ALIGN(cbMaxModSegs, KPRF_SIZEOF(MODSEG), 32);
+    KPRF_SETMIN_ALIGN(cMaxThreads, 1, 1);
+    KPRF_SETMIN_ALIGN(cMaxStacks, 1, 1);
+    KPRF_SETMIN_ALIGN(cMaxStackFrames, 32, 32);
+
+    /*
+     * Calc the size from the input.
+     * We do not take overflows into account, stupid user means stupid result.
+     */
+    KU32 cb = KPRF_OFFSETOF(HDR, aiFunctions[cMaxFunctions]);
+    KU32 cbTotal = KPRF_ALIGN(cb, 32);
+
+    cb = cMaxFunctions * KPRF_SIZEOF(FUNC);
+    cbTotal += KPRF_ALIGN(cb, 32);
+
+    cbTotal += cbMaxModSegs;
+
+    cb = cMaxThreads * KPRF_SIZEOF(THREAD);
+    cbTotal += KPRF_ALIGN(cb, 32);
+
+    cb = cMaxStacks * KPRF_SIZEOF(STACK);
+    cbTotal += KPRF_ALIGN(cb, 32);
+
+    cb = cMaxStackFrames * cMaxStacks * KPRF_SIZEOF(FRAME);
+    cbTotal += KPRF_ALIGN(cb, 32);
+
+    return cbTotal;
+}
+
+
+/**
+ * Initializes the profiler data set.
+ *
+ * @returns Pointer to the initialized profiler header on success.
+ * @returns NULL if the input doesn't add up.
+ *
+ * @param   pvData              Where to initialize the profiler data set.
+ * @param   cbData              The size of the available data.
+ * @param   cMaxFunctions       The max number of functions.
+ * @param   cbMaxModSeg         The max bytes for module segments.
+ * @param   cMaxThreads         The max number of threads.
+ * @param   cMaxStacks          The max number of stacks. (should be less or equal to the max number of threads)
+ * @param   cMaxStackFrames     The max number of frames on each of the stacks.
+ *
+ */
+KPRF_DECL_FUNC(KPRF_TYPE(P,HDR), Init)(void *pvData, KU32 cbData, KU32 cMaxFunctions, KU32 cbMaxModSegs,
+                                       KU32 cMaxThreads, KU32 cMaxStacks, KU32 cMaxStackFrames)
+{
+    /*
+     * Normalize the input.
+     */
+    if (!pvData)
+        return NULL;
+    KPRF_SETMIN_ALIGN(cMaxFunctions, 16, 16);
+    KPRF_SETMIN_ALIGN(cbMaxModSegs, KPRF_SIZEOF(MODSEG), 32);
+    KPRF_SETMIN_ALIGN(cMaxThreads, 1, 1);
+    KPRF_SETMIN_ALIGN(cMaxStacks, 1, 1);
+    KPRF_SETMIN_ALIGN(cMaxStackFrames, 32, 32);
+
+    /*
+     * The header.
+     */
+    KU32 off = 0;
+    KU32 cb = KPRF_OFFSETOF(HDR, aiFunctions[cMaxFunctions]);
+    cb = KPRF_ALIGN(cb, 32);
+    if (cbData < off + cb || off > off + cb)
+        return NULL;
+    KPRF_TYPE(P,HDR) pHdr = (KPRF_TYPE(P,HDR))pvData;
+
+    /* the core header */
+    pHdr->u32Magic          = 0;        /* Set at the very end */
+    pHdr->cFormatBits       = KPRF_BITS;
+    pHdr->uBasePtr          = 0;        /* Can be set afterwards using SetBasePtr. */
+#if KPRF_BITS <= 16
+    pHdr->u16Reserved       = 0;
+#endif
+#if KPRF_BITS <= 32
+    pHdr->u32Reserved       = 0;
+#endif
+    pHdr->cb                = cbData;
+    pHdr->cbAllocated       = cbData;
+
+    /* functions */
+    off += cb;
+    cb = cMaxFunctions * KPRF_SIZEOF(FUNC);
+    cb = KPRF_ALIGN(cb, 32);
+    if (cbData < off + cb || off > off + cb)
+        return NULL;
+    pHdr->cMaxFunctions     = cMaxFunctions;
+    pHdr->cFunctions        = 0;
+    pHdr->offFunctions      = off;
+    pHdr->cbFunction        = KPRF_SIZEOF(FUNC);
+
+    /* modsegs */
+    off += cb;
+    cb = KPRF_ALIGN(cbMaxModSegs, 32);
+    if (cbData < off + cb || off > off + cb)
+        return NULL;
+    pHdr->cbMaxModSegs      = cbMaxModSegs;
+    pHdr->cbModSegs         = 0;
+    pHdr->offModSegs        = off;
+
+    /* threads */
+    off += cb;
+    cb = cMaxThreads * KPRF_SIZEOF(THREAD);
+    cb = KPRF_ALIGN(cb, 32);
+    if (cbData < off + cb || off > off + cb)
+        return NULL;
+    pHdr->cMaxThreads       = cMaxThreads;
+    pHdr->cThreads          = 0;
+    pHdr->offThreads        = off;
+    pHdr->cbThread          = KPRF_SIZEOF(THREAD);
+
+    /* stacks */
+    off += cb;
+    cb = cMaxStacks * KPRF_OFFSETOF(STACK, aFrames[cMaxStackFrames]);
+    cb = KPRF_ALIGN(cb, 32);
+    if (cbData < off + cb || off > off + cb)
+        return NULL;
+    pHdr->cMaxStacks        = cMaxStacks;
+    pHdr->cStacks           = 0;
+    pHdr->offStacks         = off;
+    pHdr->cbStack           = KPRF_OFFSETOF(STACK, aFrames[cMaxStackFrames]);
+    pHdr->cMaxStackFrames   = cMaxStackFrames;
+
+    /* commandline */
+    pHdr->offCommandLine    = 0;
+    pHdr->cchCommandLine    = 0;
+
+    /* the final size */
+    pHdr->cb                = off + cb;
+
+
+    /*
+     * Done.
+     */
+    pHdr->u32Magic = KPRF_TYPE(,HDR_MAGIC);
+    return pHdr;
+}
+
Index: /trunk/kProfiler2/prfcoremodseg.cpp.h
===================================================================
--- /trunk/kProfiler2/prfcoremodseg.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfcoremodseg.cpp.h	(revision 2)
@@ -0,0 +1,193 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core Module Segment Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/**
+ * Adds a module segment.
+ *
+ * @returns Offset to the module if existing or successfully added
+ * @returns 0 if not found.
+ *
+ * @param   pHdr        The profiler header.
+ * @param   pModSeg     Pointer to the module segment to insert (it's copied of course).
+ * @param   off         The offset into the modseg area which has been searched.
+ *                      (This is relative to the first moddule segment record (at pHdr->offModSegs).)
+ */
+static KU32 KPRF_NAME(InsertModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(PC,MODSEG) pModSeg, KU32 off)
+{
+    /*
+     * Lookup the module segment, inserting it if not found (and there is room).
+     */
+    for (;;)
+    {
+        if (off >= pHdr->cbModSegs)
+        {
+            /*
+             * It was the end, let's try insert it.
+             *
+             * This is where we lock the modseg stuff. The deal is that we
+             * serialize the actual inserting without blocking lookups. This
+             * means that we may end up with potential racing inserts, but
+             * unless there is a large amount of modules being profiled that's
+             * probably not going to be much of a problem. Anyway if we race,
+             * we'll simply have to search the new additions before we add our
+             * own stuff.
+             */
+            KPRF_MODSEGS_LOCK();
+            if (off >= pHdr->cbModSegs)
+            {
+                KU32 cbModSeg = KPRF_OFFSETOF(MODSEG, szPath[pModSeg->cchPath + 1]);
+                cbModSeg = KPRF_ALIGN(cbModSeg, KPRF_SIZEOF(UPTR));
+                if (off + cbModSeg <= pHdr->cbMaxModSegs)
+                {
+                    KPRF_TYPE(P,MODSEG) pNew = KPRF_OFF2PTR(P,MODSEG, off + pHdr->offModSegs, pHdr);
+                    pNew->uBasePtr          = pModSeg->uBasePtr;
+                    pNew->cbSegmentMinusOne = pModSeg->cbSegmentMinusOne;
+                    pNew->iSegment          = pModSeg->iSegment;
+                    pNew->fLoaded           = pModSeg->fLoaded;
+                    pNew->cchPath           = pModSeg->cchPath;
+
+                    KI32 iPath = pModSeg->cchPath;
+                    do  pNew->szPath[iPath] = pModSeg->szPath[iPath];
+                    while (--iPath >= 0);
+
+                    /* commit it */
+                    KPRF_ATOMIC_SET32(&pHdr->cbModSegs, off + cbModSeg);
+                    off += pHdr->offModSegs;
+                }
+                else
+                    off = 0;
+                KPRF_MODSEGS_UNLOCK();
+                return off;
+            }
+            KPRF_MODSEGS_UNLOCK();
+            /* someone raced us, check the new entries. */
+        }
+
+        /*
+         * Match?
+         */
+        KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(P,MODSEG, off + pHdr->offModSegs, pHdr);
+        if (    pCur->uBasePtr          == pModSeg->uBasePtr
+            &&  pCur->fLoaded           == pModSeg->fLoaded
+            &&  pCur->cchPath           == pModSeg->cchPath
+            &&  pCur->iSegment          == pModSeg->iSegment
+            &&  pCur->cbSegmentMinusOne == pModSeg->cbSegmentMinusOne
+           )
+        {
+            KI32 iPath = pModSeg->cchPath;
+            for (;;)
+            {
+                if (!iPath--)
+                    return off + pHdr->offModSegs;
+                if (pModSeg->szPath[iPath] != pCur->szPath[iPath])
+                    break;
+            }
+            /* didn't match, continue searching */
+        }
+        KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]);
+        off += KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR));
+    }
+}
+
+
+/**
+ * Queries data for and inserts a new module segment.
+ *
+ *
+ * @returns Offset to the module if existing or successfully added
+ * @returns 0 if not found.
+ *
+ * @param   pHdr        The profiler header.
+ * @param   uPC         Address within the module.
+ * @param   off         The offset into the modseg area which has been searched.
+ *                      (This is relative to the first moddule segment record (at pHdr->offModSegs).)
+ */
+static KU32 KPRF_NAME(NewModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC, KU32 off)
+{
+    /*
+     * Query the module name and object of the function.
+     */
+#pragma pack(1)
+    struct
+    {
+        KPRF_TYPE(,MODSEG) ModSeg;
+        char               szMorePath[260];
+    } s;
+#pragma pack()
+    if (KPRF_GET_MODSEG(uPC + pHdr->uBasePtr, s.ModSeg.szPath, sizeof(s.ModSeg.szPath) + sizeof(s.szMorePath),
+                        &s.ModSeg.iSegment, &s.ModSeg.uBasePtr, &s.ModSeg.cbSegmentMinusOne))
+        return 0;
+    s.ModSeg.uBasePtr -= pHdr->uBasePtr;
+    s.ModSeg.fLoaded = 1;
+    s.ModSeg.cchPath = 0;
+    while (s.ModSeg.szPath[s.ModSeg.cchPath])
+        s.ModSeg.cchPath++;
+
+    return KPRF_NAME(InsertModSeg)(pHdr, &s.ModSeg, off);
+}
+
+
+/**
+ * Record a module segment.
+ *
+ * This is an internal worker for recording a module segment when adding
+ * a new function.
+ *
+ * @returns Offset to the module if existing or successfully added
+ * @returns 0 if not found.
+ *
+ * @param   pHdr        The profiler header.
+ * @param   uPC         Address within the module.
+ */
+static KU32 KPRF_NAME(RecordModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC)
+{
+    /*
+     * Lookup the module segment, inserting it if not found (and there is room).
+     */
+    KU32 off = 0;
+    KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(P,MODSEG, pHdr->offModSegs, pHdr);
+    const KU32 cbModSegs = pHdr->cbModSegs;
+    for (;;)
+    {
+        /* done and not found? */
+        if (off >= cbModSegs)
+            return KPRF_NAME(NewModSeg)(pHdr, uPC, off);
+
+        /*
+         * Match?
+         */
+        if (    pCur->fLoaded
+            &&  uPC - pCur->uBasePtr <= pCur->cbSegmentMinusOne)
+            return off + pHdr->offModSegs;
+
+        KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]);
+        cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR));
+        off += cbCur;
+        pCur = (KPRF_TYPE(PC,MODSEG))((KU8 *)pCur + cbCur);
+    }
+}
+
Index: /trunk/kProfiler2/prfcorepost.cpp.h
===================================================================
--- /trunk/kProfiler2/prfcorepost.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfcorepost.cpp.h	(revision 2)
@@ -0,0 +1,37 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core Post-Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/*
+ * Clean up all our defines.
+ */
+#undef KPRF_OFFSETOF
+#undef KPRF_ALIGN
+#undef KPRF_SETMIN_ALIGN
+#undef KPRF_PTR2OFF
+#undef KPRF_OFF2PTREx
+#undef KPRF_OFF2PTR
+
Index: /trunk/kProfiler2/prfcorepre.cpp.h
===================================================================
--- /trunk/kProfiler2/prfcorepre.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfcorepre.cpp.h	(revision 2)
@@ -0,0 +1,198 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core Pre-Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/** @def KPRF_OFF2PTR
+ * Internal helper for converting a offset to a pointer.
+ * @internal
+ */
+#define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \
+    ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KPRF_TYPE(,UPTR))pHdr) )
+
+/** @def KPRF_PTR2OFF
+ * Internal helper for converting a pointer to a offset.
+ * @internal
+ */
+#define KPRF_PTR2OFF(ptr, pHdr) \
+    ( (KPRF_TYPE(,UPTR))(ptr) - (KPRF_TYPE(,UPTR))(pHdr) )
+
+/** @def KPRF_ALIGN
+ * The usual align macro.
+ * @internal
+ */
+#define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) )
+
+/** @def KPRF_SETMIN_ALIGN
+ * Ensures a minimum and aligned value.
+ * @internal
+ */
+#define KPRF_SETMIN_ALIGN(n, min, align) \
+    do { \
+        if ((n) < (min)) \
+            (n) = (min); \
+        else { \
+            const KU32 u32 = ((n) + ( (align) - 1)) & ~((align) - 1); \
+            if (u32 >= (n)) \
+                (n) = u32; \
+        } \
+    } while (0)
+
+/** @def KPRF_OFFSETOF
+ * My usual extended OFFSETOF macro, except this returns KU32 and mangles the type name.
+ * @internal
+ */
+#define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member )
+
+/** @def PRF_SIZEOF
+ * Size of a kPrf type.
+ * @internal
+ */
+#define KPRF_SIZEOF(kPrfType)       sizeof(KPRF_TYPE(,kPrfType))
+
+
+/** @def KPRF_NOW
+ * Gets the current timestamp.
+ */
+#ifndef KPRF_NOW
+# error "KPRF_NOW isn't defined!"
+#endif
+
+/** @def KRPF_IS_ACTIVE
+ * Checks if profiling is activated or not.
+ * The idea is to use some global variable for disabling and enabling
+ * profiling in order to deal with init/term issues.
+ */
+#ifndef KPRF_IS_ACTIVE
+# define KPRF_IS_ACTIVE()           1
+#endif
+
+/** @def KPRF_GET_HDR
+ * Gets the pointer to the profiler data header.
+ */
+#ifndef KPRF_GET_HDR
+# error "KPRF_GET_HDR isn't defined!"
+#endif
+
+/** @def KPRF_GET_THREADID
+ * Gets native thread id. This must be unique.
+ */
+#ifndef KPRF_GET_THREADID
+# error "KPRF_GET_THREADID isn't defined!"
+#endif
+
+/** @def KPRF_SET_THREAD
+ * Sets the pointer to the current thread so we can get to it
+ * without doing a linear search by thread id.
+ */
+#ifndef KPRF_SET_THREAD
+# error "KPRF_SET_THREAD isn't defined!"
+#endif
+
+/** @def KPRF_GET_THREAD
+ * Gets the pointer to the current thread as set by KPRF_SET_THREAD.
+ */
+#ifndef KPRF_GET_THREAD
+# error "KPRF_GET_THREAD isn't defined!"
+#endif
+
+/** @def KPRF_MODSEGS_LOCK
+ * Lock the module segment for updating.
+ */
+#ifndef KPRF_MODSEGS_LOCK
+# define KPRF_MODSEGS_LOCK()            do { } while (0)
+#endif
+
+/** @def KPRF_MODSEGS_UNLOCK
+ * Unlock the module segments.
+ */
+#ifndef KPRF_MODSEGS_UNLOCK
+# define KPRF_MODSEGS_UNLOCK()          do { } while (0)
+#endif
+
+/** @def KPRF_THREADS_LOCK
+ * Lock the threads for updating.
+ */
+#ifndef KPRF_THREADS_LOCK
+# define KPRF_THREADS_LOCK()            do { } while (0)
+#endif
+
+/** @def KPRF_THREADS_UNLOCK
+ * Unlock the threads.
+ */
+#ifndef KPRF_THREADS_UNLOCK
+# define KPRF_THREADS_UNLOCK()          do { } while (0)
+#endif
+
+/** @def KPRF_FUNCS_READ_LOCK
+ * Lock the functions for reading.
+ */
+#ifndef KPRF_FUNCS_READ_LOCK
+# define KPRF_FUNCS_READ_LOCK()         do { } while (0)
+#endif
+
+/** @def KPRF_FUNCS_READ_UNLOCK
+ * Releases a read lock on the functions.
+ */
+#ifndef KPRF_FUNCS_READ_UNLOCK
+# define KPRF_FUNCS_READ_UNLOCK()       do { } while (0)
+#endif
+
+/** @def KPRF_FUNCS_WRITE_LOCK
+ * Lock the functions for updating.
+ */
+#ifndef KPRF_FUNCS_WRITE_LOCK
+# define KPRF_FUNCS_WRITE_LOCK()        do { } while (0)
+#endif
+
+/** @def KPRF_FUNCS_WRITE_UNLOCK
+ * Releases a write lock on the functions.
+ */
+#ifndef KPRF_FUNCS_WRITE_UNLOCK
+# define KPRF_FUNCS_WRITE_UNLOCK()      do { } while (0)
+#endif
+
+
+/** @def KPRF_ATOMIC_SET32
+ * Atomically set a 32-bit value.
+ */
+#ifndef KPRF_ATOMIC_SET32
+# define KPRF_ATOMIC_SET32(pu32, u32)   do { *(pu32) = (u32); } while (0)
+#endif
+
+/** @def KPRF_ATOMIC_SET64
+ * Atomically (well, in a safe way) adds to a 64-bit value.
+ */
+#ifndef KPRF_ATOMIC_ADD64
+# define KPRF_ATOMIC_ADD64(pu64, u64)   do { *(pu64) += (u64); } while (0)
+#endif
+
+/** @def KPRF_ATOMIC_SET64
+ * Atomically (well, in a safe way) increments a 64-bit value.
+ */
+#ifndef KPRF_ATOMIC_INC64
+# define KPRF_ATOMIC_INC64(pu64)        KPRF_ATOMIC_ADD64(pu64, 1)
+#endif
+
Index: /trunk/kProfiler2/prfcorereloc.cpp.h
===================================================================
--- /trunk/kProfiler2/prfcorereloc.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfcorereloc.cpp.h	(revision 2)
@@ -0,0 +1,43 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core SetBasePtr Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/**
+ * Set (or modify) the base pointer for the profiler.
+ *
+ * The purpose of the base pointer is to allow profiling of relocatable code. Set the
+ * base pointer right after initializing the data set, and update it when relocating
+ * the code (both by calling this function), and Bob's your uncle! :-)
+ *
+ * @param   pHdr        The header returned from the initializer.
+ * @param   uBasePtr    The new base pointer value.
+ */
+KPRF_DECL_FUNC(void, SetBasePtr)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uBasePtr)
+{
+    pHdr->uBasePtr = uBasePtr;
+}
+
+
Index: /trunk/kProfiler2/prfcoreterm.cpp.h
===================================================================
--- /trunk/kProfiler2/prfcoreterm.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfcoreterm.cpp.h	(revision 2)
@@ -0,0 +1,138 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Core Termination Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/**
+ * Unwinds and terminates all the threads, and frees the stack space.
+ *
+ * @returns The new data set size. (pHdr->cb)
+ * @param   pHdr        The profiler data set header.
+ */
+KPRF_DECL_FUNC(KU32, TerminateAll)(KPRF_TYPE(P,HDR) pHdr)
+{
+    KU64 TS = KPRF_NOW();
+    if (!pHdr)
+        return 0;
+
+    /*
+     * Iterate the threads and terminate all which are non-terminated.
+     */
+    KPRF_TYPE(P,THREAD) paThread = KPRF_OFF2PTR(P,THREAD, pHdr->offThreads, pHdr);
+    for (KU32 i = 0; i < pHdr->cThreads; i++)
+    {
+        KPRF_TYPE(P,THREAD) pCur = &paThread[i];
+        switch (pCur->enmState)
+        {
+            /* these states needs no work. */
+            case KPRF_TYPE(,THREADSTATE_TERMINATED):
+            case KPRF_TYPE(,THREADSTATE_UNUSED):
+            default:
+                break;
+
+            /* these are active and requires unwinding.*/
+            case KPRF_TYPE(,THREADSTATE_ACTIVE):
+            case KPRF_TYPE(,THREADSTATE_SUSPENDED):
+            case KPRF_TYPE(,THREADSTATE_OVERFLOWED):
+                KPRF_NAME(TerminateThread)(pHdr, pCur, TS);
+                break;
+        }
+    }
+
+
+    /*
+     * Free the stacks.
+     */
+    if (pHdr->offStacks)
+    {
+        /* only if the stack is at the end of the data set. */
+        const KU32 cbStacks = KPRF_ALIGN(pHdr->cMaxStacks * pHdr->cbStack, 32);
+        if (pHdr->offStacks + cbStacks == pHdr->cb)
+            pHdr->cb -= cbStacks;
+        pHdr->offStacks = 0;
+    }
+
+    return pHdr->cb;
+}
+
+
+/**
+ * Sets the commandline.
+ *
+ * This is typically done after TerminateAll, when the stacks has
+ * been freed up and there is plenty free space.
+ *
+ * @returns The new data set size. (pHdr->cb)
+ * @param   pHdr        The profiler data set header.
+ * @param   cArgs       The number of arguments in the array.
+ * @param   papszArgs   Pointer to an array of arguments.
+ */
+KPRF_DECL_FUNC(KU32, SetCommandLine)(KPRF_TYPE(P,HDR) pHdr, unsigned cArgs, const char * const *papszArgs)
+{
+    if (!pHdr)
+        return 0;
+
+    /*
+     * Any space at all?
+     */
+    if (pHdr->cb + 16 > pHdr->cbAllocated) /* 16 bytes min */
+        return pHdr->cb;
+
+    /*
+     * Encode untill we run out of space.
+     */
+    pHdr->offCommandLine = pHdr->cb;
+    char *psz = (char *)pHdr + pHdr->cb;
+    char *pszMax = (char *)pHdr + pHdr->cbAllocated - 1;
+    for (unsigned i = 0; i < cArgs && psz + 7 < pszMax; i++)
+    {
+        if (i > 0)
+            *psz++ = ' ';
+        *psz++ = '\'';
+        const char *pszArg = papszArgs[i];
+        while (psz < pszMax)
+        {
+            char ch = *pszArg++;
+            if (!ch)
+                break;
+            if (ch == '\'')
+            {
+                if (psz + 1 >= pszMax)
+                    break;
+                *psz++ = '\\';
+            }
+            *psz++ = ch;
+        }
+        if (psz < pszMax)
+            *psz++ = '\'';
+    }
+    *psz++ = '\0';
+    pHdr->cb = psz - (char *)pHdr;
+    pHdr->cchCommandLine = pHdr->cb - pHdr->offCommandLine - 1;
+
+    return pHdr->cb;
+}
+
+
Index: /trunk/kProfiler2/prfreader.cpp.h
===================================================================
--- /trunk/kProfiler2/prfreader.cpp.h	(revision 2)
+++ /trunk/kProfiler2/prfreader.cpp.h	(revision 2)
@@ -0,0 +1,1595 @@
+/* $Id$ */
+/** @file
+ * kProfiler Mark 2 - Reader Code Template.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kProfiler.
+ *
+ * kProfiler is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * kProfiler 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kProfiler; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/**
+ * Validates the non-header parts of a data-set.
+ *
+ * @returns true if valid.
+ * @returns false if invalid. (written description to pOut)
+ *
+ * @param   pHdr        Pointer to the data set.
+ * @param   cb          The size of the data set.
+ * @param   pOut        Where to write error messages.
+ */
+static bool KPRF_NAME(IsValid)(KPRF_TYPE(PC,HDR) pHdr, KU32 cb, FILE *pOut)
+{
+    KPRF_TYPE(,UPTR) uMaxPtr = ~(KPRF_TYPE(,UPTR))0 - pHdr->uBasePtr;
+
+    /*
+     * Iterate the module segments.
+     */
+    KU32 off = pHdr->offModSegs;
+    while (off < pHdr->offModSegs + pHdr->cbModSegs)
+    {
+        KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr);
+        KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]);
+        cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR));
+        if (cbCur + off > pHdr->offModSegs + pHdr->cbModSegs)
+        {
+            fprintf(pOut, "The module segment record at 0x%x is too long!\n", off);
+            return false;
+        }
+        if (pCur->uBasePtr > uMaxPtr)
+            fprintf(pOut, "warning: The module segment record at 0x%x has a too high base address.\n", off);
+
+        if (strlen(pCur->szPath) != pCur->cchPath)
+        {
+            fprintf(pOut, "The module segment record at 0x%x has an invalid path length 0x%x it the actual length is 0x%x\n",
+                    pCur->cchPath, strlen(pCur->szPath));
+            return false;
+        }
+
+        /* next */
+        off += cbCur;
+    }
+
+
+    /*
+     * Iterate the functions.
+     */
+    KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr);
+    for (KU32 i = 0; i < pHdr->cFunctions; i++)
+    {
+        KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i];
+        if (pCur->uEntryPtr > uMaxPtr)
+            fprintf(pOut, "warning: Function 0x%x has a too high base address.\n", i);
+        if (pCur->offModSeg)
+        {
+            if (    pCur->offModSeg < pHdr->offModSegs
+                ||  pCur->offModSeg >= pHdr->offModSegs + pHdr->cbModSegs
+                ||  pCur->offModSeg != KPRF_ALIGN(pCur->offModSeg, sizeof(pCur->uEntryPtr))
+               )
+            {
+                fprintf(pOut, "Function 0x%x has an invalid offModSeg value (0x%x).\n", i, pCur->offModSeg);
+                return false;
+            }
+            /** @todo more validation here.. */
+        }
+    }
+
+
+    /*
+     * Validate the threads.
+     */
+    KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr);
+    for (KU32 i = 0; i < pHdr->cThreads; i++)
+    {
+        KPRF_TYPE(PC,THREAD) pCur = &paThreads[i];
+        if (pCur->uStackBasePtr > uMaxPtr)
+            fprintf(pOut, "warning: Thread 0x%x has a too high base address.\n", i);
+        switch (pCur->enmState)
+        {
+            case KPRF_TYPE(,THREADSTATE_ACTIVE):
+            case KPRF_TYPE(,THREADSTATE_SUSPENDED):
+            case KPRF_TYPE(,THREADSTATE_OVERFLOWED):
+            case KPRF_TYPE(,THREADSTATE_TERMINATED):
+                break;
+            default:
+                fprintf(pOut, "Thread 0x%x has an invalid state value (0x%x).\n", i, pCur->enmState);
+                return false;
+        }
+    }
+
+
+    return true;
+}
+
+
+/**
+ * Dumps a file of a particular format.
+ *
+ * @returns 0 on success. (you might want to check the pOut state)
+ * @returns -1 on failure.
+ *
+ * @param   pHdr        Pointer to the data set.
+ * @param   pOut        The output file. This is opened for text writing.
+ * @param   pReader     The reader object.
+ */
+static int KPRF_NAME(Dump)(KPRF_TYPE(PC,HDR) pHdr, FILE *pOut)
+{
+    /*
+     * Any commandline?
+     */
+    if (pHdr->offCommandLine)
+        fprintf(pOut,
+                "Commandline: %s (%d  bytes)\n",
+                (char *)KPRF_OFF2PTR(PC,MODSEG, pHdr->offCommandLine, pHdr), /* stupid, stupid, type hacking. */
+                pHdr->cchCommandLine);
+
+    /*
+     * Dump the module segments.
+     */
+    fprintf(pOut,
+            "Module Segments: off=0x%x 0x%x/0x%x (bytes)\n"
+            "----------------\n",
+            pHdr->offModSegs, pHdr->cbModSegs, pHdr->cbMaxModSegs);
+    KU32 off = pHdr->offModSegs;
+    while (off < pHdr->offModSegs + pHdr->cbModSegs)
+    {
+        KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr);
+        KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]);
+        cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR));
+
+        fprintf(pOut,
+                "0x%04x: iSegment=0x%08x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n",
+                off, pCur->iSegment, pCur->uBasePtr, pCur->szPath, pCur->cchPath);
+
+        /* next */
+        off += cbCur;
+    }
+    fprintf(pOut, "\n");
+
+    /*
+     * Dump the functions.
+     */
+    fprintf(pOut,
+            "Functions: off=0x%x 0x%x/0x%x\n"
+            "----------\n",
+            pHdr->offFunctions, pHdr->cFunctions, pHdr->cMaxFunctions);
+    KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr);
+    for (KU32 i = 0; i < pHdr->cFunctions; i++)
+    {
+        KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i];
+        fprintf(pOut, "0x%04x: uEntryPtr=%" KPRF_FMT_UPTR " cOnStack=0x%" KPRF_FMT_X64 " cCalls=0x%" KPRF_FMT_X64 "\n"
+                      "       OnStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n"
+                      "  OnTopOfStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n",
+                i, pCur->uEntryPtr, pCur->cOnStack, pCur->cCalls,
+                pCur->OnStack.MinTicks, pCur->OnStack.MaxTicks,  pCur->OnStack.SumTicks,
+                pCur->OnTopOfStack.MinTicks, pCur->OnTopOfStack.MaxTicks,  pCur->OnTopOfStack.SumTicks);
+        if (pCur->offModSeg)
+        {
+            KPRF_TYPE(PC,MODSEG) pModSeg = KPRF_OFF2PTR(PC,MODSEG, pCur->offModSeg, pHdr);
+            fprintf(pOut, "  offModSeg=0x%08x iSegment=0x%02x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n",
+                    pCur->offModSeg, pModSeg->iSegment, pModSeg->uBasePtr, pModSeg->szPath, pModSeg->cchPath);
+
+#if 1
+            PKDBGMOD pMod;
+            int rc = kDbgModuleOpen(&pMod, pModSeg->szPath, NULL /* pLdrMod */);
+            if (!rc)
+            {
+                KDBGSYMBOL Sym;
+                rc = kDbgModuleQuerySymbol(pMod, pModSeg->iSegment, pCur->uEntryPtr - pModSeg->uBasePtr, &Sym);
+                if (!rc)
+                {
+                    fprintf(pOut, "  %s\n", Sym.szName);
+                }
+                kDbgModuleClose(pMod);
+            }
+#endif
+
+        }
+    }
+    fprintf(pOut, "\n");
+
+    /*
+     * Dump the threads.
+     */
+    fprintf(pOut,
+            "Threads: off=0x%x 0x%x/0x%x (Stacks=0x%x/0x%x cMaxStackFrames=0x%x)\n"
+            "--------\n",
+            pHdr->offThreads, pHdr->cThreads, pHdr->cMaxThreads, pHdr->cStacks, pHdr->cMaxStacks, pHdr->cMaxStackFrames);
+    KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr);
+    for (KU32 i = 0; i < pHdr->cThreads; i++)
+    {
+        KPRF_TYPE(PC,THREAD) pCur = &paThreads[i];
+        fprintf(pOut,
+                "0x%02x: ThreadId=0x%08" KPRF_FMT_X64 " enmState=%d szName='%s'\n"
+                "  uStackBasePtr=%" KPRF_FMT_UPTR " cbMaxStack=%" KPRF_FMT_UPTR "\n"
+                "  cCalls=0x%" KPRF_FMT_X64 " cOverflows=0x%" KPRF_FMT_X64 " cStackSwitchRejects=0x%" KPRF_FMT_X64 "\n"
+                "  cUnwinds=0x%" KPRF_FMT_X64 " ProfiledTicks=0x%" KPRF_FMT_X64 " OverheadTicks=0x%" KPRF_FMT_X64 "\n",
+                i, pCur->ThreadId, pCur->enmState, pCur->szName,
+                pCur->uStackBasePtr, pCur->cbMaxStack,
+                pCur->cCalls, pCur->cOverflows, pCur->cStackSwitchRejects,
+                pCur->cUnwinds, pCur->ProfiledTicks, pCur->OverheadTicks);
+    }
+
+    return 0;
+}
+
+
+/** Pointer to a report module.
+ * @internal */
+typedef struct KPRF_TYPE(,REPORTMOD) *KPRF_TYPE(P,REPORTMOD);
+/** Pointer to a report module segment.
+ * @internal */
+typedef struct KPRF_TYPE(,REPORTMODSEG) *KPRF_TYPE(P,REPORTMODSEG);
+
+
+/**
+ * A report module segment.
+ *
+ * @internal
+ */
+typedef struct KPRF_TYPE(,REPORTMODSEG)
+{
+    /** AVL node core. The key is the data set offset of the module segment record. */
+    KDBGADDR                    offSegment;
+    struct KPRF_TYPE(,REPORTMODSEG) *mpLeft;    /**< AVL left branch. */
+    struct KPRF_TYPE(,REPORTMODSEG) *mpRight;   /**< AVL rigth branch. */
+    /** Pointer to the next segment for the module. */
+    KPRF_TYPE(P,REPORTMODSEG)   pNext;
+    /** Pointer to the module segment data in the data set. */
+    KPRF_TYPE(PC,MODSEG)        pModSeg;
+    /** Pointer to the module this segment belongs to. */
+    KPRF_TYPE(P,REPORTMOD)      pMod;
+    /** The time this segment has spent on the stack.. */
+    KU64                        OnStackTicks;
+    /** The time this segment has spent on the top of the stack.. */
+    KU64                        OnTopOfStackTicks;
+    /** The number of profiled functions from this segment. */
+    KU32                        cFunctions;
+    KU8                         mHeight;        /**< AVL Subtree height. */
+} KPRF_TYPE(,REPORTMODSEG), *KPRF_TYPE(P,REPORTMODSEG);
+
+/* Instantiate the AVL tree code. */
+#define KAVL_CHECK_FOR_EQUAL_INSERT
+#define KAVL_MAX_STACK          32
+#define KAVL_STD_KEY_COMP
+#define mKey                    offSegment
+#define KAVLKEY                 KDBGADDR
+#define KAVLNODE                KPRF_TYPE(,REPORTMODSEG)
+#define KAVL_FN(name)           KPRF_NAME(ReportTree ## name)
+#define KAVL_TYPE(prefix,name)  KPRF_TYPE(prefix, REPORTMODESEG ## name)
+#define KAVL_INT(name)          KPRF_NAME(REPORTMODESEGINT ## name)
+#define KAVL_DECL(type)         K_DECL_INLINE(type)
+#include <k/kAvlTmpl/kAvlBase.h>
+#include <k/kAvlTmpl/kAvlDestroy.h>
+#include <k/kAvlTmpl/kAvlGet.h>
+#include <k/kAvlTmpl/kAvlUndef.h>
+
+
+/**
+ * A report module segment.
+ *
+ * @internal
+ */
+typedef struct KPRF_TYPE(,REPORTMOD)
+{
+    /** The module number. */
+    KU32                        iMod;
+    /** Pointer to the next module in the list. */
+    KPRF_TYPE(P,REPORTMOD)      pNext;
+    /** Pointer to the list of segments belonging to this module. */
+    KPRF_TYPE(P,REPORTMODSEG)   pFirstSeg;
+    /** The debug module handle. */
+    PKDBGMOD                    pDbgMod;
+    /** The time this segment has spent on the stack.. */
+    KU64                        OnStackTicks;
+    /** The time this segment has spent on the top of the stack.. */
+    KU64                        OnTopOfStackTicks;
+    /** The number of profiled functions from this segment. */
+    KU32                        cFunctions;
+} KPRF_TYPE(,REPORTMOD), *KPRF_TYPE(P,REPORTMOD);
+
+
+/**
+ * A report function.
+ *
+ * @internal
+ */
+typedef struct KPRF_TYPE(,REPORTFUNC)
+{
+    /** Pointer to the function data in the data set. */
+    KPRF_TYPE(PC,FUNC)          pFunc;
+    /** Pointer to the module segment this function belongs to. (can be NULL) */
+    KPRF_TYPE(P,REPORTMODSEG)   pModSeg;
+    /** Pointer to the function symbol. */
+    PKDBGSYMBOL                 pSym;
+    /** Pointer to the function line number. */
+    PKDBGLINE                   pLine;
+} KPRF_TYPE(,REPORTFUNC), *KPRF_TYPE(P,REPORTFUNC);
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher on-stack time.
+ */
+static int KPRF_NAME(FuncCompareOnStack)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->OnStack.SumTicks > p2->OnStack.SumTicks)
+        return -1;
+    if (p1->OnStack.SumTicks < p2->OnStack.SumTicks)
+        return 1;
+    if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks)
+        return -1;
+    if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks)
+        return 1;
+    if (p1->OnStack.MinTicks > p2->OnStack.MinTicks)
+        return -1;
+    if (p1->OnStack.MinTicks < p2->OnStack.MinTicks)
+        return 1;
+    if (p1 < p2)
+        return -1;
+    return 1;
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher on-stack average time.
+ */
+static int KPRF_NAME(FuncCompareOnStackAvg)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->OnStack.SumTicks / p1->cOnStack > p2->OnStack.SumTicks / p2->cOnStack)
+        return -1;
+    if (p1->OnStack.SumTicks / p1->cOnStack < p2->OnStack.SumTicks / p2->cOnStack)
+        return 1;
+    return KPRF_NAME(FuncCompareOnStack)(pv1, pv2);
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher on-stack min time.
+ */
+static int KPRF_NAME(FuncCompareOnStackMin)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->OnStack.MinTicks > p2->OnStack.MinTicks)
+        return -1;
+    if (p1->OnStack.MinTicks < p2->OnStack.MinTicks)
+        return 1;
+    return KPRF_NAME(FuncCompareOnStack)(pv1, pv2);
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher on-stack max time.
+ */
+static int KPRF_NAME(FuncCompareOnStackMax)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks)
+        return -1;
+    if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks)
+        return 1;
+    return KPRF_NAME(FuncCompareOnStack)(pv1, pv2);
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher on-stack time.
+ */
+static int KPRF_NAME(FuncCompareOnTopOfStack)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->OnTopOfStack.SumTicks > p2->OnTopOfStack.SumTicks)
+        return -1;
+    if (p1->OnTopOfStack.SumTicks < p2->OnTopOfStack.SumTicks)
+        return 1;
+    if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks)
+        return -1;
+    if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks)
+        return 1;
+    if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks)
+        return -1;
+    if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks)
+        return 1;
+    if (p1 < p2)
+        return -1;
+    return 1;
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher on-stack average time.
+ */
+static int KPRF_NAME(FuncCompareOnTopOfStackAvg)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->OnTopOfStack.SumTicks / p1->cOnStack > p2->OnTopOfStack.SumTicks / p2->cOnStack)
+        return -1;
+    if (p1->OnTopOfStack.SumTicks / p1->cOnStack < p2->OnTopOfStack.SumTicks / p2->cOnStack)
+        return 1;
+    return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2);
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher on-stack min time.
+ */
+static int KPRF_NAME(FuncCompareOnTopOfStackMin)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks)
+        return -1;
+    if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks)
+        return 1;
+    return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2);
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher on-stack min time.
+ */
+static int KPRF_NAME(FuncCompareOnTopOfStackMax)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks)
+        return -1;
+    if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks)
+        return 1;
+    return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2);
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher call to count.
+ */
+static int KPRF_NAME(FuncCompareCallsTo)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->cOnStack > p2->cOnStack)
+        return -1;
+    if (p1->cOnStack < p2->cOnStack)
+        return 1;
+    return KPRF_NAME(FuncCompareOnStack)(pv1, pv2);
+}
+
+
+/**
+ * Compares two REPROTFUNC records to determin which has the higher call from count.
+ */
+static int KPRF_NAME(FuncCompareCallsFrom)(const void *pv1, const void *pv2)
+{
+    KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
+    KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
+    if (p1->cCalls > p2->cCalls)
+        return -1;
+    if (p1->cCalls < p2->cCalls)
+        return 1;
+    return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2);
+}
+
+
+/**
+ * A report thread.
+ *
+ * @internal
+ */
+typedef struct KPRF_TYPE(,REPORTTHREAD)
+{
+    /** Pointer to the thread data in the data set. */
+    KPRF_TYPE(PC,THREAD)        pThread;
+} KPRF_TYPE(,REPORTTHREAD), *KPRF_TYPE(P,REPORTTHREAD);
+
+
+/**
+ * Data-set analysis report.
+ *
+ * This is an internal structure to store temporary data between the
+ * analysis stage and the priting state.
+ *
+ * @internal
+ */
+typedef struct KPRF_TYPE(,REPORT)
+{
+    /** Pointer to the data set. */
+    KPRF_TYPE(PC,HDR)           pHdr;
+
+    /** @name Data-set item wrappers.
+     * @{ */
+    /** Pointer to the array of threads. */
+    KPRF_TYPE(P,REPORTTHREAD)   paThreads;
+    /** Pointer to the array of functions. */
+    KPRF_TYPE(P,REPORTFUNC)     paFunctions;
+    /** Pointer to the head of the module list. */
+    KPRF_TYPE(P,REPORTMOD)      pFirstMod;
+    /** The number of modules in the list. */
+    KU32                        cMods;
+    /** The module segment tree. */
+    KPRF_TYPE(P,REPORTMODSEG)   pModSegTree;
+    /** The number of module segments in the tree. */
+    KU32                        cModSegs;
+    /** @} */
+
+    /** @name Sorting.
+     * @{ */
+    /** Pointer to the array of threads. */
+    KPRF_TYPE(P,REPORTTHREAD)  *papSortedThreads;
+    /** Pointer to the array of functions. */
+    KPRF_TYPE(P,REPORTFUNC)    *papSortedFunctions;
+    /** @} */
+
+    /** @name Accumulated Thread Data.
+     * @{ */
+    /** Sum of the profiled ticks. */
+    KU64                        ProfiledTicks;
+    /** Sum of the overhead ticks. */
+    KU64                        OverheadTicks;
+    /** Sum of the sleep ticks. */
+    KU64                        SleepTicks;
+    /** Sum of calls performed. */
+    KU64                        cCalls;
+    /** @} */
+
+} KPRF_TYPE(,REPORT), *KPRF_TYPE(P,REPORT), **KPRF_TYPE(PP,REPORT);
+
+
+/**
+ * Allocates and initializes a report.
+ *
+ * @returns Pointer to the report on success.
+ * @returns NULL on failure.
+ */
+static KPRF_TYPE(P,REPORT) KPRF_NAME(NewReport)(KPRF_TYPE(PC,HDR) pHdr)
+{
+    /*
+     * Allocate memory for the report.
+     * Everything but the mods and modsegs is allocated in the same block as the report.
+     */
+    KSIZE cb = KPRF_ALIGN(KPRF_SIZEOF(REPORT), 32);
+    KUPTR offThreads = cb;
+    cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTTHREAD) * pHdr->cThreads, 32);
+    KUPTR offFunctions = cb;
+    cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTFUNC) * pHdr->cFunctions, 32);
+    KUPTR offSortedThreads = cb;
+    cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTTHREAD)) * pHdr->cThreads, 32);
+    KUPTR offSortedFunctions = cb;
+    cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTFUNC)) * pHdr->cFunctions, 32);
+    KPRF_TYPE(P,REPORT) pReport = (KPRF_TYPE(P,REPORT))malloc(cb);
+    if (!pReport)
+        return NULL;
+
+    /*
+     * Initialize it.
+     */
+    pReport->pHdr = pHdr;
+    pReport->paThreads = (KPRF_TYPE(P,REPORTTHREAD))((KU8 *)pReport + offThreads);
+    pReport->paFunctions = (KPRF_TYPE(P,REPORTFUNC))((KU8 *)pReport + offFunctions);
+    pReport->pFirstMod = NULL;
+    pReport->cMods = 0;
+    pReport->pModSegTree = NULL;
+    pReport->cModSegs = 0;
+    pReport->papSortedThreads = (KPRF_TYPE(P,REPORTTHREAD) *)((KU8 *)pReport + offSortedThreads);
+    pReport->papSortedFunctions = (KPRF_TYPE(P,REPORTFUNC) *)((KU8 *)pReport + offSortedFunctions);
+    pReport->ProfiledTicks = 0;
+    pReport->OverheadTicks = 0;
+    pReport->SleepTicks = 0;
+    pReport->cCalls = 0;
+
+    return pReport;
+}
+
+
+/**
+ * AVL callback for deleting a module segment node.
+ *
+ * @returns 0
+ * @param   pCore       The tree node to delete.
+ * @param   pvParam     User parameter, ignored.
+ */
+static int KPRF_NAME(DeleteModSeg)(KPRF_TYPE(P,REPORTMODSEG) pCore, void *pvParam)
+{
+    free(pCore);
+    return 0;
+}
+
+
+/**
+ * Releases all the resources held be a report.
+ *
+ * @param   pReport     The report to delete.
+ */
+static void KPRF_NAME(DeleteReport)(KPRF_TYPE(P,REPORT) pReport)
+{
+    /*
+     * The list and AVL.
+     */
+    while (pReport->pFirstMod)
+    {
+        KPRF_TYPE(P,REPORTMOD) pFree = pReport->pFirstMod;
+        pReport->pFirstMod = pFree->pNext;
+        kDbgModuleClose(pFree->pDbgMod);
+        free(pFree);
+    }
+
+    KPRF_NAME(ReportTreeDestroy)(&pReport->pModSegTree, KPRF_NAME(DeleteModSeg), NULL);
+
+    /*
+     * The function debug info.
+     */
+    KU32 i = pReport->pHdr->cFunctions;
+    while (i-- > 0)
+    {
+        kDbgSymbolFree(pReport->paFunctions[i].pSym);
+        kDbgLineFree(pReport->paFunctions[i].pLine);
+    }
+
+    /*
+     * The report it self.
+     */
+    pReport->pHdr = NULL;
+    free(pReport);
+}
+
+
+/**
+ * Builds the module segment tree and the list of modules.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ * @param   pReport     The report to work on.
+ */
+static int KPRF_NAME(AnalyzeModSegs)(KPRF_TYPE(P,REPORT) pReport)
+{
+    const KU32 offEnd = pReport->pHdr->offModSegs + pReport->pHdr->cbModSegs;
+    KU32 off = pReport->pHdr->offModSegs;
+    while (off < offEnd)
+    {
+        KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pReport->pHdr);
+        KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]);
+        cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR));
+
+        /*
+         * Create a new modseg record.
+         */
+        KPRF_TYPE(P,REPORTMODSEG) pSeg = (KPRF_TYPE(P,REPORTMODSEG))malloc(sizeof(*pSeg));
+        if (!pSeg)
+            return -1;
+
+        pSeg->offSegment = off;
+        pSeg->pModSeg = pCur;
+        pSeg->pMod = NULL; /* below */
+        pSeg->OnStackTicks = 0;
+        pSeg->OnTopOfStackTicks = 0;
+        pSeg->cFunctions = 0;
+
+        if (!KPRF_NAME(ReportTreeInsert)(&pReport->pModSegTree, pSeg))
+        {
+            free(pSeg);
+            return -1;
+        }
+        pReport->cModSegs++;
+
+        /*
+         * Search for the module record.
+         */
+        KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod;
+        while (     pMod
+               &&   (   pMod->pFirstSeg->pModSeg->cchPath != pCur->cchPath
+                     || memcmp(pMod->pFirstSeg->pModSeg->szPath, pCur->szPath, pCur->cchPath)))
+            pMod = pMod->pNext;
+        if (pMod)
+        {
+            /** @todo sort segments */
+            pSeg->pMod = pMod;
+            pSeg->pNext = pMod->pFirstSeg;
+            pMod->pFirstSeg = pSeg;
+        }
+        else
+        {
+            KPRF_TYPE(P,REPORTMOD) pMod = (KPRF_TYPE(P,REPORTMOD))malloc(sizeof(*pMod) + pCur->cchPath);
+            if (!pMod)
+                return -1;
+            pSeg->pMod = pMod;
+            pSeg->pNext = NULL;
+            pMod->iMod = pReport->cMods++;
+            pMod->pNext = pReport->pFirstMod;
+            pReport->pFirstMod = pMod;
+            pMod->pFirstSeg = pSeg;
+            pMod->pDbgMod = NULL;
+            pMod->OnStackTicks = 0;
+            pMod->OnTopOfStackTicks = 0;
+            pMod->cFunctions = 0;
+
+            int rc = kDbgModuleOpen(&pMod->pDbgMod, pSeg->pModSeg->szPath, NULL /* kLdrMod */);
+            if (rc)
+                pMod->pDbgMod = NULL;
+        }
+
+        /* next */
+        off += cbCur;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Initializes the function arrays.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ * @param   pReport     The report to work on.
+ */
+static int KPRF_NAME(AnalyseFunctions)(KPRF_TYPE(P,REPORT) pReport)
+{
+    KU32 iFunc = pReport->pHdr->cFunctions;
+    KPRF_TYPE(PC,FUNC) pFunc = KPRF_OFF2PTR(PC,FUNC, pReport->pHdr->offFunctions + iFunc * sizeof(*pFunc), pReport->pHdr);
+    KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc];
+    while (iFunc-- > 0)
+    {
+        pFunc--;
+        pReportFunc--;
+
+        pReport->papSortedFunctions[iFunc] = pReportFunc;
+        pReportFunc->pFunc = pFunc;
+        pReportFunc->pModSeg = KPRF_NAME(ReportTreeGet)(&pReport->pModSegTree, pFunc->offModSeg);
+        pReportFunc->pSym = NULL;
+        pReportFunc->pLine = NULL;
+        if (pReportFunc->pModSeg)
+        {
+            /* Collect module segment and module statistics. */
+            KPRF_TYPE(P,REPORTMODSEG) pModSeg = pReportFunc->pModSeg;
+            pModSeg->cFunctions++;
+            pModSeg->OnStackTicks += pFunc->OnStack.SumTicks;
+            pModSeg->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks;
+
+            KPRF_TYPE(P,REPORTMOD) pMod = pModSeg->pMod;
+            pMod->cFunctions++;
+            pMod->OnStackTicks += pFunc->OnStack.SumTicks;
+            pMod->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks;
+
+            /* Get debug info. */
+            KDBGADDR offSegment = pFunc->uEntryPtr - pModSeg->pModSeg->uBasePtr;
+            int rc = kDbgModuleQuerySymbolA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pSym);
+            /** @todo check displacement! */
+            if (rc)
+                pReportFunc->pSym = NULL;
+            rc = kDbgModuleQueryLineA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pLine);
+            if (rc)
+                pReportFunc->pLine = NULL;
+        }
+    }
+    return 0;
+}
+
+
+/**
+ * Initializes the thread arrays.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ * @param   pReport     The report to work on.
+ */
+static int KPRF_NAME(AnalyseThreads)(KPRF_TYPE(P,REPORT) pReport)
+{
+    KU32 iThread = pReport->pHdr->cThreads;
+    KPRF_TYPE(PC,THREAD) pThread = KPRF_OFF2PTR(PC,THREAD, pReport->pHdr->offThreads + iThread * sizeof(*pThread), pReport->pHdr);
+    KPRF_TYPE(P,REPORTTHREAD) pReportThread = &pReport->paThreads[iThread];
+    while (iThread-- > 0)
+    {
+        pThread--;
+        pReportThread--;
+
+        pReport->papSortedThreads[iThread] = pReportThread;
+        pReportThread->pThread = pThread;
+
+        /* collect statistics */
+        pReport->ProfiledTicks += pThread->ProfiledTicks;
+        pReport->OverheadTicks += pThread->OverheadTicks;
+        pReport->SleepTicks += pThread->SleepTicks;
+        pReport->cCalls += pThread->cCalls;
+
+    }
+    return 0;
+}
+
+
+/**
+ * Analyses the data set, producing a report.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ *
+ * @param   pHdr        The data set.
+ * @param   ppReport    Where to store the report.
+ */
+static int KPRF_NAME(Analyse)(KPRF_TYPE(PC,HDR) pHdr, KPRF_TYPE(PP,REPORT) ppReport)
+{
+    *ppReport = NULL;
+
+    /* allocate it */
+    KPRF_TYPE(P,REPORT) pReport = KPRF_NAME(NewReport)(pHdr);
+    if (!pReport)
+        return -1;
+
+    /* read module segments */
+    int rc = KPRF_NAME(AnalyzeModSegs)(pReport);
+    if (!rc)
+    {
+        /* read functions. */
+        rc = KPRF_NAME(AnalyseFunctions)(pReport);
+        if (!rc)
+        {
+            /* read threads */
+            rc = KPRF_NAME(AnalyseThreads)(pReport);
+            if (!rc)
+            {
+                *ppReport = pReport;
+                return 0;
+            }
+        }
+    }
+
+    KPRF_NAME(DeleteReport)(pReport);
+    return rc;
+}
+
+
+/**
+ * Writes row with 32-bit value.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowU32X32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit)
+{
+    fprintf(pOut,
+            "  <tr>\n"
+            "    <th>%s</th>\n"
+            "    <td colspan=\"6\">%u (0x%x)%s%s</td>\n"
+            "  </tr>\n",
+            pszName,
+            u32, u32, pszUnit ? " " : "", pszUnit ? pszUnit : "");
+}
+
+
+/**
+ * Writes row with 32-bit value.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowU32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit)
+{
+    fprintf(pOut,
+            "  <tr>\n"
+            "    <th>%s</th>\n"
+            "    <td colspan=\"6\">%u%s%s</td>\n"
+            "  </tr>\n",
+            pszName,
+            u32, pszUnit ? " " : "", pszUnit ? pszUnit : "");
+}
+
+
+/**
+ * Writes row with 64-bit value.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowU64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit)
+{
+    fprintf(pOut,
+            "  <tr>\n"
+            "    <th>%s</th>\n"
+            "    <td colspan=\"6\">% " KPRF_FMT_U64 " (0x%" KPRF_FMT_X64 ")%s%s</td>\n"
+            "  </tr>\n",
+            pszName,
+            u64, u64, pszUnit ? " " : "", pszUnit ? pszUnit : "");
+}
+
+
+/**
+ * Writes row with 64-bit hex value.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowX64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit)
+{
+    fprintf(pOut,
+            "  <tr>\n"
+            "    <th>%s</th>\n"
+            "    <td colspan=\"6\">0x%" KPRF_FMT_X64 "%s%s</td>\n"
+            "  </tr>\n",
+            pszName,
+            u64, pszUnit ? " " : "", pszUnit ? pszUnit : "");
+}
+
+
+/**
+ * Writes a ticks.
+ */
+static void KPRF_NAME(HtmlWriteParts)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks)
+{
+    /** U+2030 PER MILLE SIGN */
+    static const KU8 s_szPerMilleSignUtf8[4] = { 0xe2, 0x80, 0xb0, 0};
+
+    if (cTicks * 100 / cTotalTicks)
+    {
+        KU32 u = (KU32)((cTicks * 1000) / cTotalTicks);
+        fprintf(pOut, "%u.%01u%%", u / 10, u %10);
+    }
+    else //if (cTicks * 100000 / cTotalTicks)
+    {
+        KU32 u = (KU32)((cTicks * 100000) / cTotalTicks);
+        fprintf(pOut, "%u.%02u%s", u / 100, u % 100, s_szPerMilleSignUtf8);
+    }
+    /*
+    else if (cTicks * 1000000 / cTotalTicks)
+        fprintf(pOut, "%u ppm", (unsigned)((cTicks * 1000000) / cTotalTicks));
+    else
+        fprintf(pOut, "%u ppb", (unsigned)((cTicks * 1000000000) / cTotalTicks));
+    */
+}
+
+
+/**
+ * Writes a ticks.
+ */
+static void KPRF_NAME(HtmlWriteTicks)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks)
+{
+    fprintf(pOut, "%" KPRF_FMT_U64 "", cTicks);
+    if (cTotalTicks)
+    {
+        fprintf(pOut, "</td><td class=\"PartsRow\">");
+        KPRF_NAME(HtmlWriteParts)(pOut, cTicks, cTotalTicks);
+    }
+}
+
+
+/**
+ * Writes row with ticks value.
+ *
+ * @param   pOut            Where to write.
+ * @aaran   pszName         The row name.
+ * @param   cTicks          The tick count.
+ * @param   cTotalTicks     If non-zero, this is used for cTicks / cTotalTicks.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowTicks)(FILE *pOut, const char *pszName, KU64 cTicks, KU64 cTotalTicks)
+{
+    fprintf(pOut,
+            "  <tr>\n"
+            "    <th class=\"TicksRow\">%s</th>\n"
+            "    <td class=\"TicksRow\">",
+            pszName);
+    KPRF_NAME(HtmlWriteTicks)(pOut, cTicks, cTotalTicks);
+    fprintf(pOut,
+                     "</td><td colspan=\"%d\"/>\n"
+            "  </tr>\n",
+            cTotalTicks ? 4 : 5);
+}
+
+
+/**
+ * Writes row with a time stat value.
+ *
+ * @param   pOut            Where to write.
+ * @aaran   pszName         The row name.
+ * @param   cTicks          The tick count.
+ * @param   cTotalTicks     If non-zero, this is used for cTicks / cTotalTicks.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowTimeStat)(FILE *pOut, const char *pszName, KPRF_TYPE(PC,TIMESTAT) pTimeStat, KU64 cTotalTicks)
+{
+    fprintf(pOut,
+            "  <tr>\n"
+            "    <th class=\"TicksRow\">%s</th>\n"
+            "    <td class=\"TicksRow\">",
+            pszName);
+    KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->SumTicks, cTotalTicks);
+    fprintf(pOut,    "</td>\n"
+            "    <td class=\"MinMaxTicksRow\">");
+    KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MinTicks, cTotalTicks);
+    fprintf(pOut,    "</td>\n"
+            "    <td class=\"MinMaxTicksRow\">");
+    KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MaxTicks, cTotalTicks);
+    fprintf(pOut,    "</td>\n"
+            "  </tr>\n");
+}
+
+
+/**
+ * Writes row with calls value.
+ *
+ * @param   pOut            Where to write.
+ * @aaran   pszName         The row name.
+ * @param   cCalls          The call count.
+ * @param   cTotalCalls     This is used for cCalls / cTotalCalls.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowCalls)(FILE *pOut, const char *pszName, KU64 cCalls, KU64 cTotalCalls)
+{
+    fprintf(pOut,
+            "  <tr>\n"
+            "    <th class=\"CallsRow\">%s</th>\n"
+            "    <td class=\"CallsRow\">%" KPRF_FMT_U64"</td><td class=\"PartsRow\">",
+            pszName, cCalls);
+    KPRF_NAME(HtmlWriteParts)(pOut, cCalls, cTotalCalls);
+    fprintf(pOut, "</td><td colspan=4></td>"
+            "  </tr>\n");
+}
+
+
+/**
+ * Writes row with pointer value.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowUPTR)(FILE *pOut, const char *pszName, KPRF_TYPE(,UPTR) uPtr, const char *pszUnit)
+{
+    fprintf(pOut,
+            "  <tr>\n"
+            "    <th>%s</th>\n"
+            "    <td colspan=\"6\">%" KPRF_FMT_UPTR "%s%s</td>\n"
+            "  </tr>\n",
+            pszName,
+            uPtr, pszUnit ? " " : "", pszUnit ? pszUnit : "");
+}
+
+
+/**
+ * Writes row with string value.
+ * @internal
+ */
+static void KPRF_NAME(HtmlWriteRowString)(FILE *pOut, const char *pszName, const char *pszClass, const char *pszFormat, ...)
+{
+    fprintf(pOut,
+             "  <tr>\n"
+             "    <th>%s</th>\n"
+             "    <td%s%s%s colspan=\"6\">",
+             pszName,
+             pszClass ? " class=\"" : "", pszClass ? pszClass : "", pszClass ? "\"" : "");
+    va_list va;
+    va_start(va, pszFormat);
+    vfprintf(pOut, pszFormat, va);
+    va_end(va);
+    fprintf(pOut,      "</td>\n"
+             "  </tr>\n");
+}
+
+
+/**
+ * The first column
+ */
+typedef enum KPRF_TYPE(,FIRSTCOLUMN)
+{
+    KPRF_TYPE(,FIRSTCOLUMN_ON_STACK) = 0,
+    KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK),
+    KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO),
+    KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM),
+    KPRF_TYPE(,FIRSTCOLUMN_MAX)
+} KPRF_TYPE(,FIRSTCOLUMN);
+
+
+/**
+ * Prints the table with the sorted functions.
+ * The tricky bit is that the sorted column should be to the left of the function name.
+ */
+static void KPRF_NAME(HtmlWriteSortedFunctions)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut, const char *pszName,
+                                                const char *pszTitle, KPRF_TYPE(,FIRSTCOLUMN) enmFirst)
+{
+    fprintf(pOut,
+            "<h2><a name=\"%s\">%s</a></h2>\n"
+            "\n",
+            pszName, pszTitle);
+
+    fprintf(pOut,
+            "<table class=\"FunctionsSorted\">\n"
+            "  <tr>\n"
+            "    <th/>\n");
+    static const char *s_pszHeaders[KPRF_TYPE(,FIRSTCOLUMN_MAX) * 2] =
+    {
+        "    <th colspan=8><a href=\"#Functions-TimeOnStack\">Time On Stack</a> (ticks)</th>\n",
+        "    <th colspan=2><a href=\"#Functions-TimeOnStack\">Sum</a></th>\n"
+        "    <th colspan=2><a href=\"#Functions-TimeOnStack-Min\">Min</a></th>\n"
+        "    <th colspan=2><a href=\"#Functions-TimeOnStack-Avg\">Average</a></th>\n"
+        "    <th colspan=2><a href=\"#Functions-TimeOnStack-Max\">Max</a></th>\n",
+
+        "    <th colspan=8><a href=\"#Functions-TimeOnTopOfStack\">Time On To Top</a> (ticks)</th>\n",
+        "    <th colspan=2><a href=\"#Functions-TimeOnTopOfStack\">Sum</a></th>\n"
+        "    <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Min\">Min</a></th>\n"
+        "    <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Avg\">Average</a></th>\n"
+        "    <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Max\">Max</a></th>\n",
+
+        "    <th colspan=2><a href=\"#Functions-CallsTo\">Calls To</a></th>\n",
+        "    <th/><th/>\n",
+
+        "    <th colspan=2><a href=\"#Functions-CallsFrom\">Calls From</a></th>\n",
+        "    <th/><th/>\n",
+    };
+
+    fprintf(pOut, "%s",  s_pszHeaders[enmFirst * 2]);
+    fprintf(pOut, "    <th>Function</th>\n");
+    for (unsigned i = (enmFirst + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); i != enmFirst; i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX))
+        fprintf(pOut, "%s",  s_pszHeaders[i * 2]);
+    fprintf(pOut,
+            "  </tr>\n"
+            "  <tr>\n"
+            "    <th/>\n");
+    fprintf(pOut, "%s",  s_pszHeaders[enmFirst * 2 + 1]);
+    fprintf(pOut, "    <th/>\n");
+    for (unsigned i = (enmFirst + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); i != enmFirst; i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX))
+        fprintf(pOut, "%s",  s_pszHeaders[i * 2 + 1]);
+    fprintf(pOut,
+            "  </tr>\n");
+
+    for (KU32 iFunc = 0; iFunc < pReport->pHdr->cFunctions; iFunc++)
+    {
+        KPRF_TYPE(P,REPORTFUNC) pReportFunc = pReport->papSortedFunctions[iFunc];
+        KPRF_TYPE(PC,FUNC) pFunc = pReportFunc->pFunc;
+        fprintf(pOut,
+                "  <tr>\n"
+                "    <td>%u</td>\n",
+               iFunc);
+
+        unsigned i = enmFirst;
+        do
+        {
+            switch (i)
+            {
+                case KPRF_TYPE(,FIRSTCOLUMN_ON_STACK):
+                    fprintf(pOut,
+                            "    <td class=\"Ticks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+                            pFunc->OnStack.SumTicks);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.SumTicks, pReport->ProfiledTicks);
+                    fprintf(pOut,       "</td>\n"
+                            "    <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+                            pFunc->OnStack.MinTicks);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks);
+                    fprintf(pOut,       "</td>\n"
+                            "    <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+                            pFunc->OnStack.SumTicks / pFunc->cOnStack);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks);
+                    fprintf(pOut,       "</td>\n"
+                            "    <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+                            pFunc->OnStack.MaxTicks);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MaxTicks, pReport->ProfiledTicks);
+                    fprintf(pOut,       "</td>\n");
+                    break;
+
+                case KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK):
+                    fprintf(pOut,
+                            "    <td class=\"Ticks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+                            pFunc->OnTopOfStack.SumTicks);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.SumTicks, pReport->ProfiledTicks);
+                    fprintf(pOut,       "</td>\n"
+                            "    <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+                            pFunc->OnTopOfStack.MinTicks);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks);
+                    fprintf(pOut,       "</td>\n"
+                            "    <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+                            pFunc->OnTopOfStack.SumTicks / pFunc->cOnStack);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks);
+                    fprintf(pOut,       "</td>\n"
+                            "    <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
+                            pFunc->OnTopOfStack.MaxTicks);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MaxTicks, pReport->ProfiledTicks);
+                    fprintf(pOut,       "</td>\n");
+                    break;
+
+                case KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO):
+                    fprintf(pOut,
+                            "    <td class=\"Calls\">%" KPRF_FMT_U64 "</td><td Class=\"Parts\">",
+                            pFunc->cOnStack);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cOnStack, pReport->cCalls);
+                    fprintf(pOut,       "</td>\n");
+                    break;
+
+                case KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM):
+                    fprintf(pOut,
+                            "    <td class=\"Calls\">%" KPRF_FMT_U64 "</td><td Class=\"Parts\">",
+                            pFunc->cCalls);
+                    KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cOnStack, pReport->cCalls);
+                    fprintf(pOut,       "</td>\n");
+                    break;
+
+                default:
+                    break;
+            }
+
+            /* inject the function column */
+            if (i == enmFirst)
+            {
+                fprintf(pOut,
+                        "    <td><a href=\"#Func-%u\">",
+                        pReportFunc - pReport->paFunctions);
+                if (pReportFunc->pSym)
+                    fprintf(pOut, "%s</a></td>\n", pReportFunc->pSym->szName);
+                else
+                    fprintf(pOut, "%" KPRF_FMT_UPTR "</a></td>\n", pFunc->uEntryPtr);
+            }
+
+            /* next */
+            i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX);
+        } while (i != enmFirst);
+
+        fprintf(pOut,
+                "  </tr>\n");
+    }
+    fprintf(pOut,
+            "</table>\n"
+            "\n");
+
+}
+
+
+/**
+ * Writes an HTML report.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ * @param   pReport     The report to put into HTML.
+ * @param   pOut        The file stream to write the HTML to.
+ */
+static int KPRF_NAME(WriteHtmlReport)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut)
+{
+    KPRF_TYPE(PC,HDR) pHdr = pReport->pHdr;
+
+    /*
+     * Write the standard html.
+     */
+    fprintf(pOut,
+            "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
+            "<html>\n"
+            "<head>\n"
+            "  <meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">\n"
+            "  <title>kProfiler 2 - %s</title>\n"
+            "</head>\n"
+            "<style>\n"
+            "table\n"
+            "{\n"
+//            "  width: 90%%;\n"
+            "  background: #999999;\n"
+//            "  margin-top: .6em;\n"
+//            "  margin-bottom: .3em;\n"
+            "}\n"
+            "th\n"
+            "{\n"
+            "  padding: 1px 4px;\n"
+            "  background: #cccccc;\n"
+//            "  text-align: left;\n"
+            "  font-size: 90%%;\n"
+            //"  width: 30%%;\n"
+            "}\n"
+            "td\n"
+            "{\n"
+            "  padding: 1px 4px;\n"
+            "  background: #ffffff;\n"
+            "  font-size: 90%%;\n"
+            "}\n"
+            "td.Ticks\n"
+            "{\n"
+            "  text-align: right;\n"
+            "}\n"
+            "td.TicksRow\n"
+            "{\n"
+            "  text-align: right;\n"
+            "}\n"
+            "td.MinMaxTicks\n"
+            "{\n"
+            "  text-align: right;\n"
+            "}\n"
+            "td.MinMaxTicksRow\n"
+            "{\n"
+            "  text-align: right;\n"
+            "}\n"
+            "td.Parts\n"
+            "{\n"
+            "  text-align: right;\n"
+            "}\n"
+            "td.PartsRow\n"
+            "{\n"
+            "  text-align: left;\n"
+            "}\n"
+            "td.Calls\n"
+            "{\n"
+            "  text-align: right;\n"
+            "}\n"
+            "td.CallsRow\n"
+            "{\n"
+            "  text-align: right;\n"
+            "}\n"
+            "td.BlankRow\n"
+            "{\n"
+            "  background: #e0e0e0;\n"
+            "}\n"
+            "td.Name\n"
+            "{\n"
+            "  font-weight: bold;\n"
+            "}\n"
+            "table.Summary th\n"
+            "{\n"
+            "  width:200px;\n"
+            "}\n"
+            "table.Thread\n"
+            "{\n"
+            "  min-width:60%%\n"
+            "}\n"
+            "table.Thread th\n"
+            "{\n"
+            "  width:200px;\n"
+            "}\n"
+            "table.Functions\n"
+            "{\n"
+            "  width:60%%;\n"
+            "}\n"
+            "table.Functions th\n"
+            "{\n"
+            "  width:200px;\n"
+            "}\n"
+            "table.Modules\n"
+            "{\n"
+            "  width:60%%;\n"
+            "}\n"
+            "table.Modules th\n"
+            "{\n"
+            "  width:200px;\n"
+            "}\n"
+            "table.FunctionsSorted\n"
+            "{\n"
+            "}\n"
+            "</style>\n"
+            "<body topmargin=\"0\">\n"
+            ,
+            pHdr->offCommandLine
+                ? (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr)
+                : ""
+            );
+
+    /*
+     * Table of contents.
+     */
+    fprintf(pOut,
+            "<h2>Table of Contents</h2>\n"
+            "\n"
+            "<ul>\n"
+            "  <li><a href=\"#Summary\"  >1.0 Summary</a></li>\n"
+            "  <li><a href=\"#Functions\">2.0 Functions</a></li>\n"
+            "      <ul>\n"
+            "        <li><a href=\"#Functions-TimeOnStack\"     >2.1 Time On Stack</a></li>\n"
+            "          <ul>\n"
+            "            <li><a href=\"#Functions-TimeOnStack-Avg\"     >2.2.1 Time On Stack - Average</a></li>\n"
+            "            <li><a href=\"#Functions-TimeOnStack-Min\"     >2.2.1 Time On Stack - Min</a></li>\n"
+            "            <li><a href=\"#Functions-TimeOnStack-Max\"     >2.2.2 Time On Stack - Max</a></li>\n"
+            "          </ul>\n"
+            "        <li><a href=\"#Functions-TimeOnTopOfStack\">2.3 Time On Top Of Stack</a></li>\n"
+            "          <ul>\n"
+            "            <li><a href=\"#Functions-TimeOnTopOfStack-Avg\">2.3.1 Time On Top Of Stack - Average</a></li>\n"
+            "            <li><a href=\"#Functions-TimeOnTopOfStack-Min\">2.3.2 Time On Top Of Stack - Min</a></li>\n"
+            "            <li><a href=\"#Functions-TimeOnTopOfStack-Max\">2.3.3 Time On Top Of Stack - Max</a></li>\n"
+            "          </ul>\n"
+            "        <li><a href=\"#Functions-CallsTo\"         >2.3 Calls To</a></li>\n"
+            "        <li><a href=\"#Functions-CallsFrom\"       >2.4 Calls From</a></li>\n"
+            "        <li><a href=\"#Function-Details\"          >2.5 Function Details</a></li>\n"
+            "      </ul>\n"
+            "  <li><a href=\"#Threads\"  >3.0 Threads</a></li>\n"
+            "  <li><a href=\"#Modules\"  >4.0 Modules</a></li>\n"
+            "</ul>\n"
+            "\n"
+            "\n");
+
+    /*
+     * Summary.
+     */
+    fprintf(pOut,
+            "<h2><a name=\"Summary\">1.0 Summary</a></h2>\n"
+            "\n"
+            "<p>\n"
+            "<table class=\"Summary\">\n");
+    if (pHdr->offCommandLine)
+        KPRF_NAME(HtmlWriteRowString)(pOut, "Command Line", NULL, "%s", (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr));
+    KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Threads", pHdr->cThreads, NULL);
+    KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Modules", pReport->cMods, NULL);
+    KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Functions", pHdr->cFunctions, NULL);
+    KPRF_NAME(HtmlWriteRowTicks)(pOut, "Profiled", pReport->ProfiledTicks, pReport->ProfiledTicks);
+    KPRF_NAME(HtmlWriteRowTicks)(pOut, "Sleep", pReport->SleepTicks, pReport->ProfiledTicks);
+    KPRF_NAME(HtmlWriteRowTicks)(pOut, "Overhead", pReport->OverheadTicks, pReport->ProfiledTicks + pReport->OverheadTicks);
+    KPRF_NAME(HtmlWriteRowCalls)(pOut, "Recorded Calls", pReport->cCalls, pReport->cCalls);
+    fprintf(pOut, "<tr><td class=\"BlankRow\" colspan=7>&nbsp;</td></tr>\n");
+    KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Version ", NULL, "Mark 2 Alpha 1");
+    KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Build Time ", NULL, __DATE__ " " __TIME__);
+    fprintf(pOut,
+            "</table>\n"
+            "</p>\n"
+            "\n"
+            "\n");
+
+    /*
+     * Functions.
+     */
+    fprintf(pOut,
+            "<h2><a name=\"Functions\">2.0 Functions</a></h2>\n"
+            "\n");
+
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStack));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack",     "2.1 Time On Stack", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK));
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackAvg));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Avg",     "2.2.1 Time On Stack - Average", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK));
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackMin));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Min",     "2.2.2 Time On Stack - Min", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK));
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackMax));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Max",     "2.2.3 Time On Stack - Max", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK));
+
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStack));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack",    "2.2 Time On Top Of Stack", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK));
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackAvg));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Avg","2.2.1 Time On Top Of Stack - Average", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK));
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackMin));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Min","2.2.2 Time On Top Of Stack - Min", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK));
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackMax));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Max","2.2.3 Time On Top Of Stack - Max", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK));
+
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareCallsTo));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-CallsTo",         "2.4 Calls To", KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO));
+
+    qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareCallsFrom));
+    KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-CallsFrom",       "2.5 Calls From", KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM));
+
+    fprintf(pOut,
+            "<h2><a name=\"Function-Details\">2.5 Function Details</a></h2>\n"
+            "\n"
+            "<p>\n"
+            "<table class=\"Functions\">\n");
+    for (KU32 iFunc = 0; iFunc < pHdr->cFunctions; iFunc++)
+    {
+        KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc];
+        KPRF_TYPE(PC,FUNC) pFunc = pReportFunc->pFunc;
+
+        fprintf(pOut,
+                "<tr><td class=\"BlankRow\" colspan=7><a name=\"Func-%u\">&nbsp;</a></td></tr>\n",
+                iFunc);
+        KPRF_NAME(HtmlWriteRowU32)(pOut, "Function No.", iFunc, NULL);
+        if (pReportFunc->pSym)
+            KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pReportFunc->pSym->szName);
+        if (pReportFunc->pLine)
+            KPRF_NAME(HtmlWriteRowString)(pOut, "Location", NULL, "<a href=\"file:///%s\">%s</a> Line #%d",
+                                          pReportFunc->pLine->szFile, pReportFunc->pLine->szFile, pReportFunc->pLine->iLine);
+        if (pReportFunc->pModSeg)
+        {
+            KPRF_NAME(HtmlWriteRowString)(pOut, "Module", NULL, "<a href=\"#Mod-%u\">%s</a>",
+                                          pReportFunc->pModSeg->pMod->iMod, pReportFunc->pModSeg->pModSeg->szPath);
+            KPRF_NAME(HtmlWriteRowString)(pOut, "Segment:Offset", NULL, "%x:%" KPRF_FMT_UPTR,
+                                          pReportFunc->pModSeg->pModSeg->iSegment,
+                                          pFunc->uEntryPtr - pReportFunc->pModSeg->pModSeg->uBasePtr);
+        }
+        KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Address", pFunc->uEntryPtr, NULL);
+
+        KPRF_NAME(HtmlWriteRowTimeStat)(pOut, "On Stack", &pFunc->OnStack, pReport->ProfiledTicks);
+        KPRF_NAME(HtmlWriteRowTimeStat)(pOut, "On Top Of Stack", &pFunc->OnTopOfStack, pReport->ProfiledTicks);
+        KPRF_NAME(HtmlWriteRowCalls)(pOut, "Calls To", pFunc->cOnStack, pReport->cCalls);
+        KPRF_NAME(HtmlWriteRowCalls)(pOut, "Calls From", pFunc->cCalls, pReport->cCalls);
+
+        fprintf(pOut,
+                "\n");
+    }
+    fprintf(pOut,
+            "</table>\n"
+            "</p>\n"
+            "\n");
+
+    /*
+     * Threads.
+     */
+    fprintf(pOut,
+            "<h2><a name=\"Threads\">3.0 Threads</a></h2>\n"
+            "\n"
+            "<p>\n"
+            "<table class=\"Threads\">\n");
+
+    for (KU32 iThread = 0; iThread < pHdr->cThreads; iThread++)
+    {
+        KPRF_TYPE(PC,THREAD) pThread = pReport->paThreads[iThread].pThread;
+
+        fprintf(pOut,
+                "<tr><td class=\"BlankRow\" colspan=7><a name=\"Thread-%u\">&nbsp;</a></td></tr>\n",
+                iThread);
+        KPRF_NAME(HtmlWriteRowU32)(pOut, "Thread No.", iThread, NULL);
+        KPRF_NAME(HtmlWriteRowX64)(pOut, "Thread Id", pThread->ThreadId, NULL);
+        if (pThread->szName[0])
+            KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pThread->szName);
+        KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Stack Base Address", pThread->uStackBasePtr, NULL);
+        KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Max Stack Depth", pThread->cbMaxStack, "bytes");
+        //KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Max Stack Depth", pThread->cMaxFrames, "frames"); /** @todo max stack frames! */
+        KPRF_NAME(HtmlWriteRowTicks)(pOut, "Profiled", pThread->ProfiledTicks, pReport->ProfiledTicks);
+        KPRF_NAME(HtmlWriteRowTicks)(pOut, "Sleep", pThread->SleepTicks, pReport->ProfiledTicks);
+        KPRF_NAME(HtmlWriteRowTicks)(pOut, "Overhead", pThread->OverheadTicks, pReport->ProfiledTicks + pReport->OverheadTicks);
+        KPRF_NAME(HtmlWriteRowCalls)(pOut, "Recorded Calls",  pThread->cCalls, pReport->cCalls);
+        KPRF_NAME(HtmlWriteRowU64)(pOut, "Unwinds", pThread->cUnwinds, NULL);
+        KPRF_NAME(HtmlWriteRowU64)(pOut, "Profiler Stack Overflows", pThread->cOverflows, NULL);
+        KPRF_NAME(HtmlWriteRowU64)(pOut, "Profiler Stack Switch Rejects", pThread->cStackSwitchRejects, NULL);
+
+        fprintf(pOut,
+                "\n");
+    }
+    fprintf(pOut,
+            "</table>\n"
+            "</p>\n"
+            "\n");
+
+
+    /*
+     * Modules.
+     */
+    fprintf(pOut,
+            "<h2><a name=\"Modules\">4.0 Modules</a></h2>\n"
+            "\n"
+            "<p>\n"
+            "<table class=\"Modules\">\n");
+
+    KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod;
+    KU32 iMod = 0;
+    while (pMod)
+    {
+        fprintf(pOut,
+                "<a name=\"Mod-%u\">\n"
+                "<tr><td class=\"BlankRow\" colspan=7><a name=\"Module-%u\">&nbsp;</a></td></tr>\n",
+                iMod);
+        KPRF_NAME(HtmlWriteRowU32)(pOut, "Module No.", iMod, NULL);
+        KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pMod->pFirstSeg->pModSeg->szPath);
+
+        for (KPRF_TYPE(P,REPORTMODSEG) pSeg = pMod->pFirstSeg; pSeg; pSeg = pSeg->pNext)
+        {
+            char szName[64];
+            sprintf(szName, "Segment No.%u - Base", pSeg->pModSeg->iSegment);
+            KPRF_NAME(HtmlWriteRowUPTR)(pOut, szName, pSeg->pModSeg->uBasePtr, NULL);
+            sprintf(szName, "Segment No.%u - Size", pSeg->pModSeg->iSegment);
+            KPRF_NAME(HtmlWriteRowUPTR)(pOut, szName,
+                                        pSeg->pModSeg->cbSegmentMinusOne + 1 > pSeg->pModSeg->cbSegmentMinusOne
+                                        ? pSeg->pModSeg->cbSegmentMinusOne + 1
+                                        : pSeg->pModSeg->cbSegmentMinusOne,
+                                        NULL);
+        }
+
+        KPRF_NAME(HtmlWriteRowTicks)(pOut, "On Stack", pMod->OnStackTicks, pReport->ProfiledTicks);
+        KPRF_NAME(HtmlWriteRowTicks)(pOut, "On Top Of Stack", pMod->OnTopOfStackTicks, pReport->ProfiledTicks);
+        KPRF_NAME(HtmlWriteRowU32)(pOut, "Functions", pMod->cFunctions, NULL);
+
+        fprintf(pOut,
+                "\n");
+
+        /* next */
+        iMod++;
+        pMod = pMod->pNext;
+    }
+    fprintf(pOut,
+            "</table>\n"
+            "</p>\n"
+            "\n");
+
+
+    /*
+     * The End.
+     */
+    fprintf(pOut,
+            "</body>\n"
+            "</html>\n");
+    return 0;
+}
Index: /trunk/kProfiler2/prfx86msc.asm
===================================================================
--- /trunk/kProfiler2/prfx86msc.asm	(revision 2)
+++ /trunk/kProfiler2/prfx86msc.asm	(revision 2)
@@ -0,0 +1,389 @@
+; $Id$
+;; @file
+; kProfiler Mark 2 - Microsoft C/C++ Compiler Interaction, x86.
+;
+
+;
+; Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+;
+; This file is part of kProfiler.
+;
+; kProfiler is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; kProfiler 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
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with kProfiler; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+;
+
+
+[section .data]
+;
+g_fCalibrated:
+        dd 0
+g_OverheadAdj:
+        dd 0
+
+[section .text]
+
+extern KPRF_ENTER
+extern KPRF_LEAVE
+
+global __penter
+global __pexit
+
+;ifdef  UNDEFINED
+global common_return_path
+global common_overhead
+global common_no_overhead
+global calibrate
+global calib_inner_update_minimum
+global calib_inner_next
+global calib_outer_dec
+global calib_outer_inc
+global calib_done
+global calib_nullproc
+;endif
+
+
+;;
+; On x86 the call to this function has been observed to be put before
+; creating the stack frame, as the very first instruction in the function.
+;
+; Thus the stack layout is as follows:
+;       24      return address of the calling function.
+;       20      our return address - the address of the calling function + 5.
+;       1c      eax
+;       18      edx
+;       14      eflags
+;       10      ecx
+;       c       tsc high       - param 3
+;       8       tsc low
+;       4       frame pointer  - param 2
+;       0       function ptr   - param 1
+;
+;
+align 16
+__penter:
+        ; save volatile register and get the time stamp.
+        push    eax
+        push    edx
+        rdtsc
+        pushfd
+        push    ecx
+
+        ; setting up the enter call frame (cdecl).
+        sub     esp, 4 + 4 + 8
+        mov     [esp + 0ch], edx        ; Param 3 - the timestamp
+        mov     [esp + 08h], eax
+        lea     edx, [esp + 24h]        ; Param 2 - frame pointer (pointer to the return address of the function calling us)
+        mov     [esp + 04h], edx
+        mov     eax, [esp + 20h]        ; Param 1 - The function address
+        sub     eax, 5                  ; call instruction
+        mov     [esp], eax
+
+        call    KPRF_ENTER
+        jmp     common_return_path
+
+
+;;
+; On x86 the call to this function has been observed to be put right before
+; return instruction. This fact matters since since we have to calc the same
+; stack address as in _penter.
+;
+; Thus the stack layout is as follows:
+;       24      return address of the calling function.
+;       20      our return address - the address of the calling function + 5.
+;       1c      eax
+;       18      edx
+;       14      eflags
+;       10      ecx
+;       c       tsc high       - param 3
+;       8       tsc low
+;       4       frame pointer  - param 2
+;       0       function ptr   - param 1
+;
+;
+align 16
+__pexit:
+        ; save volatile register and get the time stamp.
+        push    eax
+        push    edx
+        rdtsc
+        pushfd
+        push    ecx
+
+        ; setting up the leave call frame (cdecl).
+        sub     esp, 4 + 4 + 8
+        mov     [esp + 0ch], edx        ; Param 3 - the timestamp
+        mov     [esp + 08h], eax
+        lea     edx, [esp + 24h]        ; Param 2 - frame pointer (pointer to the return address of the function calling us)
+        mov     [esp + 04h], edx
+        mov     eax, [esp + 20h]        ; Param 1 - Some address in the function.
+        sub     eax, 5                  ; call instruction
+        mov     [esp], eax
+
+        call    KPRF_LEAVE
+        jmp common_return_path
+
+
+;;
+; This is the common return path for both the enter and exit hooks.
+; It's kept common because we can then use the same overhead adjustment
+; and save some calibration efforts. It also saves space :-)
+align 16
+common_return_path:
+        ; Update overhead
+        test    eax, eax
+        jz      common_no_overhead
+        cmp     byte [g_fCalibrated], 0
+        jnz     common_overhead
+        call    calibrate
+common_overhead:
+        mov     ecx, eax                ; ecx <- pointer to overhead counter.
+        mov     eax, [g_OverheadAdj]    ; apply the adjustment before reading tsc
+        sub     [esp + 08h], eax
+        sbb     dword [esp + 0ch], 0
+
+        rdtsc
+        sub     eax, [esp + 08h]
+        sbb     edx, [esp + 0ch]
+        add     [ecx], eax
+        adc     [ecx + 4], edx
+common_no_overhead:
+        add     esp, 4 + 4 + 8
+
+        ; restore volatile registers.
+        pop     ecx
+        popfd
+        pop     edx
+        pop     eax
+        ret
+
+;;
+; Data esi points to while we're calibrating.
+struc CALIBDATA
+    .OverheadLo resd 1
+    .OverheadHi resd 1
+    .ProfiledLo resd 1
+    .ProfiledHi resd 1
+    .EnterTSLo  resd 1
+    .EnterTSHi  resd 1
+    .MinLo      resd 1
+    .MinHi      resd 1
+endstruc
+
+
+
+align 16
+;;
+; Do necessary calibrations.
+;
+calibrate:
+        ; prolog
+        push    ebp
+        mov     ebp, esp
+        pushfd
+        pushad
+        sub     esp, CALIBDATA_size
+        mov     esi, esp                ; esi points to the CALIBDATA
+
+        ;
+        ; Indicate that we have finished calibrating.
+        ;
+        mov     eax, 1
+        xchg    dword [g_fCalibrated], eax
+
+        ;
+        ; The outer loop - find the right adjustment.
+        ;
+        mov     ebx, 200h               ; loop counter.
+calib_outer_loop:
+
+        ;
+        ; The inner loop - calls the function number of times to establish a
+        ;                  good minimum value
+        ;
+        mov     ecx, 200h
+        mov     dword [esi + CALIBDATA.MinLo], 0ffffffffh
+        mov     dword [esi + CALIBDATA.MinHi], 07fffffffh
+calib_inner_loop:
+
+        ; zero the overhead and profiled times.
+        xor     eax, eax
+        mov     [esi + CALIBDATA.OverheadLo], eax
+        mov     [esi + CALIBDATA.OverheadHi], eax
+        mov     [esi + CALIBDATA.ProfiledLo], eax
+        mov     [esi + CALIBDATA.ProfiledHi], eax
+        call    calib_nullproc
+
+        ; subtract the overhead
+        mov     eax, [esi + CALIBDATA.ProfiledLo]
+        mov     edx, [esi + CALIBDATA.ProfiledHi]
+        sub     eax, [esi + CALIBDATA.OverheadLo]
+        sbb     edx, [esi + CALIBDATA.OverheadHi]
+
+        ; update the minimum value.
+        test    edx, 080000000h
+        jnz near calib_outer_dec        ; if negative, just simplify and shortcut
+        cmp     edx, [esi + CALIBDATA.MinHi]
+        jg      calib_inner_next
+        jl      calib_inner_update_minimum
+        cmp     eax, [esi + CALIBDATA.MinLo]
+        jge     calib_inner_next
+calib_inner_update_minimum:
+        mov     [esi + CALIBDATA.MinLo], eax
+        mov     [esi + CALIBDATA.MinHi], edx
+calib_inner_next:
+        loop    calib_inner_loop
+
+        ; Is the minimum value acceptable?
+        test    dword [esi + CALIBDATA.MinHi], 80000000h
+        jnz     calib_outer_dec         ; simplify if negative.
+        cmp     dword [esi + CALIBDATA.MinHi], 0
+        jnz     calib_outer_inc         ; this shouldn't be possible
+        cmp     dword [esi + CALIBDATA.MinLo], 1fh
+        jbe     calib_outer_dec         ; too low - 2 ticks per pair is the minimum!
+        cmp     dword [esi + CALIBDATA.MinLo], 30h
+        jbe     calib_done              ; this is fine!
+calib_outer_inc:
+        inc     dword [g_OverheadAdj]
+        jmp     calib_outer_next
+calib_outer_dec:
+        cmp     dword [g_OverheadAdj], 1
+        je      calib_done
+        dec     dword [g_OverheadAdj]
+calib_outer_next:
+        dec     ebx
+        jnz     calib_outer_loop
+calib_done:
+
+        ; epilog
+        add     esp, CALIBDATA_size
+        popad
+        popfd
+        leave
+        ret
+
+
+
+
+;;
+; The calibration __penter - this must be identical to the real thing except for the KPRF call.
+align 16
+calib_penter:
+        ; This part must be identical
+        push    eax
+        push    edx
+        rdtsc
+        pushfd
+        push    ecx
+
+        ; store the entry
+        mov     [esi + CALIBDATA.EnterTSLo], eax
+        mov     [esi + CALIBDATA.EnterTSHi], edx
+
+        ; create the call frame
+        push    edx
+        push    eax
+        push    0
+        push    0
+
+        lea     eax, [esi + CALIBDATA.OverheadLo]
+        jmp     common_overhead
+
+
+;;
+; The calibration __pexit - this must be identical to the real thing except for the KPRF call.
+align 16
+calib_pexit:
+        ; This part must be identical
+        push    eax
+        push    edx
+        rdtsc
+        pushfd
+        push    ecx
+
+        ; update the time
+        push    eax
+        push    edx
+        sub     eax, [esi + CALIBDATA.EnterTSLo]
+        sbb     edx, [esi + CALIBDATA.EnterTSHi]
+        add     [esi + CALIBDATA.ProfiledLo], eax
+        adc     [esi + CALIBDATA.ProfiledHi], edx
+        pop     edx
+        pop     eax
+
+        ; create the call frame
+        push    edx
+        push    eax
+        push    0
+        push    0
+
+        lea     eax, [esi + CALIBDATA.EnterTSLo]
+        jmp     common_overhead
+
+
+;;
+; The 'function' we're profiling.
+; The general idea is that each pair should take something like 2-10 ticks.
+;
+; (Btw. If we don't use multiple pairs here, we end up with the wrong result.)
+align 16
+calib_nullproc:
+        call    calib_penter ;0
+        call    calib_pexit
+
+        call    calib_penter ;1
+        call    calib_pexit
+
+        call    calib_penter ;2
+        call    calib_pexit
+
+        call    calib_penter ;3
+        call    calib_pexit
+
+        call    calib_penter ;4
+        call    calib_pexit
+
+        call    calib_penter ;5
+        call    calib_pexit
+
+        call    calib_penter ;6
+        call    calib_pexit
+
+        call    calib_penter ;7
+        call    calib_pexit
+
+        call    calib_penter ;8
+        call    calib_pexit
+
+        call    calib_penter ;9
+        call    calib_pexit
+
+        call    calib_penter ;a
+        call    calib_pexit
+
+        call    calib_penter ;b
+        call    calib_pexit
+
+        call    calib_penter ;c
+        call    calib_pexit
+
+        call    calib_penter ;d
+        call    calib_pexit
+
+        call    calib_penter ;e
+        call    calib_pexit
+
+        call    calib_penter ;f
+        call    calib_pexit
+        ret
+
Index: /trunk/kProfiler2/tst.c
===================================================================
--- /trunk/kProfiler2/tst.c	(revision 2)
+++ /trunk/kProfiler2/tst.c	(revision 2)
@@ -0,0 +1,48 @@
+#include <stdio.h>
+
+#ifdef _MSC_VER
+void __cdecl _penter(void);
+void __cdecl _pexit(void);
+__declspec(naked) int  naked(void)
+{
+    __asm
+    {
+        call    _penter
+        call    _pexit
+        xor     eax, eax
+        ret
+    }
+}
+
+#endif
+
+int bar(void)
+{
+    unsigned i;
+    for (i = 0; i < 1000; i += 7)
+        i += i & 1;
+    return i;
+}
+
+int foo(void)
+{
+    unsigned i, rc = 0;
+    for (i = 0; i < 1000; i++)
+        rc += bar();
+#ifdef _MSC_VER
+    for (; i < 2000; i++)
+        rc += naked();
+#endif
+    return i;
+}
+
+int main()
+{
+    int rc;
+    printf("hello");
+    fflush(stdout);
+    rc = foo();
+    printf("world\n");
+    return rc;
+}
+
Index: /trunk/kProfiler2/tstlongjmp.c
===================================================================
--- /trunk/kProfiler2/tstlongjmp.c	(revision 2)
+++ /trunk/kProfiler2/tstlongjmp.c	(revision 2)
@@ -0,0 +1,62 @@
+
+#include <setjmp.h>
+#include <time.h>
+
+/* just try trick the compiler into not optimizing stuff by
+   making it "uncertain" which path to take. */
+int always_true(void)
+{
+    time_t t = time(NULL);
+    if (t == time(NULL))
+        return 1;
+    if (t != time(NULL))
+        return 1;
+    if (t == time(NULL))
+        return 1;
+    if (t != time(NULL))
+        return 1;
+    return 0;
+}
+
+jmp_buf g_JmpBuf;
+
+int onelevel(void)
+{
+    if (always_true())
+        longjmp(g_JmpBuf, 1);
+    return 0;
+}
+
+
+int twolevels_inner(void)
+{
+    if (always_true())
+        longjmp(g_JmpBuf, 1);
+    return 0;
+}
+
+int twolevels_outer(void)
+{
+    int rc;
+    always_true();
+    rc = twolevels_inner();
+    always_true();
+    return rc;
+}
+
+
+int main()
+{
+    int rc = 1;
+
+    /* first */
+    if (!setjmp(g_JmpBuf))
+        rc = onelevel();
+
+    /* second */
+    if (!setjmp(g_JmpBuf))
+        rc = twolevels_outer();
+
+    return rc != 1;
+}
+
Index: /trunk/kRdr/Makefile.kmk
===================================================================
--- /trunk/kRdr/Makefile.kmk	(revision 2)
+++ /trunk/kRdr/Makefile.kmk	(revision 2)
@@ -0,0 +1,44 @@
+# $Id$
+## @file
+# kRdr - The File Provider, sub-makefile.
+#
+
+#
+# Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+#
+# This file is part of kStuff.
+#
+# kStuff is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# kStuff 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with kStuff; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#
+
+DEPTH ?= ../..
+SUB_DEPTH = ..
+include $(PATH_KBUILD)/subheader.kmk
+
+#
+# kRdrStatic - The file provider module.
+#
+LIBRARIES += kRdrStatic
+kRdrStatic_TEMPLATE = kStuffLIB
+kRdrStatic_DEFS = KDBG_BUILDING
+kRdrStatic_SOURCES = \
+	kRdr.cpp \
+	kRdrFile.cpp \
+	kRdrBuffered.cpp
+
+# Generate the rules
+include $(PATH_KBUILD)/subfooter.kmk
+
Index: /trunk/kRdr/kRdr.cpp
===================================================================
--- /trunk/kRdr/kRdr.cpp	(revision 2)
+++ /trunk/kRdr/kRdr.cpp	(revision 2)
@@ -0,0 +1,284 @@
+/* $Id$ */
+/** @file
+ * kRdr - The File Provider.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kRdrInternal.h"
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The list of file providers. */
+static PCKRDROPS g_pRdrHead = &g_kRdrFileOps;
+
+
+/**
+ * Adds a new file provider.
+ *
+ * @param   pAdd        The new file provider.
+ */
+KRDR_DECL(void) kRdrAddProvider(PKRDROPS pAdd)
+{
+    pAdd->pNext = g_pRdrHead;
+    g_pRdrHead = pAdd;
+}
+
+
+/**
+ * Tries to opens a file.
+ *
+ * @returns 0 on success, OS status code on failure.
+ * @param   ppRdr           Where to store the file provider instance.
+ * @param   pszFilename     The filename.
+ */
+KRDR_DECL(int) kRdrOpen(PPKRDR ppRdr, const char *pszFilename)
+{
+    int             rc = -1;
+    PCKRDROPS    pCur;
+    for (pCur = g_pRdrHead; pCur; pCur = pCur->pNext)
+    {
+        rc = pCur->pfnCreate(ppRdr, pszFilename);
+        if (!rc)
+            return 0;
+    }
+    return rc;
+}
+
+
+/**
+ * Closes the file.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ *          On failure, the file provider instance will be in an indeterminate state - don't touch it!
+ * @param   pRdr        The file provider instance.
+ */
+KRDR_DECL(int) kRdrClose(PKRDR pRdr)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnDestroy(pRdr);
+}
+
+
+/** Read bits from the file.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBuf       Where to put the bits.
+ * @param   cb          The number of bytes to read.
+ * @param   off         Where to start reading.
+ */
+KRDR_DECL(int) kRdrRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnRead(pRdr, pvBuf, cb, off);
+}
+
+
+/** Map all the file bits into memory (read only).
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   ppvBits     Where to store the address of the mapping.
+ *                      The size can be obtained using pfnSize.
+ */
+KRDR_DECL(int) kRdrAllMap(PKRDR pRdr, const void **ppvBits)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnAllMap(pRdr, ppvBits);
+}
+
+
+/** Unmap a file bits mapping obtained by KRDROPS::pfnAllMap.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBits      The mapping address.
+ */
+KRDR_DECL(int) kRdrAllUnmap(PKRDR pRdr, const void *pvBits)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnAllUnmap(pRdr, pvBits);
+}
+
+
+/** Get the file size.
+ *
+ * @returns The file size. Returns -1 on failure.
+ * @param   pRdr        The file provider instance.
+ */
+KRDR_DECL(KFOFF) kRdrSize(PKRDR pRdr)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnSize(pRdr);
+}
+
+
+/** Get the file pointer offset.
+ *
+ * @returns The file pointer offset. Returns -1 on failure.
+ * @param   pRdr        The file provider instance.
+ */
+KRDR_DECL(KFOFF) kRdrTell(PKRDR pRdr)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnTell(pRdr);
+}
+
+
+/** Get the file name.
+ *
+ * @returns The file name. Returns NULL on failure.
+ * @param   pRdr        The file provider instance.
+ */
+KRDR_DECL(const char *) kRdrName(PKRDR pRdr)
+{
+    KRDR_VALIDATE_EX(pRdr, NULL);
+    return pRdr->pOps->pfnName(pRdr);
+}
+
+
+/** Get the native file handle if possible.
+ *
+ * @returns The native file handle. Returns -1 if not available.
+ * @param   pRdr        The file provider instance.
+ */
+KRDR_DECL(KIPTR) kRdrNativeFH(PKRDR pRdr)
+{
+    KRDR_VALIDATE_EX(pRdr, -1);
+    return pRdr->pOps->pfnNativeFH(pRdr);
+}
+
+
+/**
+ * Gets the page size used when mapping sections of the file.
+ *
+ * @returns The page size.
+ * @param   pRdr        The file provider instance.
+ */
+KRDR_DECL(KSIZE) kRdrPageSize(PKRDR pRdr)
+{
+    KRDR_VALIDATE_EX(pRdr, 0x10000);
+    return pRdr->pOps->pfnPageSize(pRdr);
+}
+
+
+/**
+ * Maps the segments of a image into memory.
+ *
+ * The file reader will be using the RVA member of each segment to figure out where
+ * it goes relative to the image base address.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   ppvBase     On input when fFixed is set, this contains the base address of the mapping.
+ *                      On output this contains the base of the image mapping.
+ * @param   cSegments   The number of segments in the array pointed to by paSegments.
+ * @param   paSegments  The segments thats going to be mapped.
+ * @param   fFixed      If set, the address at *ppvBase should be the base address of the mapping.
+ */
+KRDR_DECL(int) kRdrMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnMap(pRdr, ppvBase, cSegments, paSegments, fFixed);
+}
+
+
+/**
+ * Reloads dirty pages in mapped image.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBase      The base address of the image mapping.
+ * @param   cSegments   The number of segments in the array pointed to by paSegments.
+ * @param   paSegments  The segments thats going to be mapped.
+ */
+KRDR_DECL(int) kRdrRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnRefresh(pRdr, pvBase, cSegments, paSegments);
+}
+
+
+/**
+ * Protects or unprotects an image mapping.
+ *
+ * This is typically used for getting write access to read or execute only
+ * pages while applying fixups.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBase      The base address of the image mapping.
+ * @param   cSegments   The number of segments in the array pointed to by paSegments.
+ * @param   paSegments  The segments thats going to be mapped.
+ * @param   fUnprotectOrProtect     When set the all mapped segments are made writable.
+ *                                  When clean the segment protection is restored.
+ */
+KRDR_DECL(int) kRdrProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnProtect(pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect);
+}
+
+
+/**
+ * Unmaps a image mapping.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBase      The base address of the image mapping.
+ * @param   cSegments   The number of segments in the array pointed to by paSegments.
+ * @param   paSegments  The segments thats going to be mapped.
+ */
+KRDR_DECL(int) kRdrUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnUnmap(pRdr, pvBase, cSegments, paSegments);
+}
+
+
+/**
+ * We're done reading from the file but would like to keep file mappings.
+ *
+ * If the OS support closing the file handle while the file is mapped,
+ * the reader should do so.
+ *
+ * @param   pRdr        The file provider instance.
+ */
+KRDR_DECL(void) kRdrDone(PKRDR pRdr)
+{
+    KRDR_VALIDATE_VOID(pRdr);
+    pRdr->pOps->pfnDone(pRdr);
+}
+
Index: /trunk/kRdr/kRdrBuffered.cpp
===================================================================
--- /trunk/kRdr/kRdrBuffered.cpp	(revision 2)
+++ /trunk/kRdr/kRdrBuffered.cpp	(revision 2)
@@ -0,0 +1,751 @@
+/* $Id$ */
+/** @file
+ * kRdrBuffered - Buffered File Provider.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kRdrInternal.h"
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * The buffered file provier instance.
+ * This is just a wrapper around another file provider.
+ */
+typedef struct KRDRBUF
+{
+    /** The file reader vtable. */
+    KRDR                Core;
+    /** The actual file provider that we're wrapping. */
+    PKRDR               pRdr;
+    /** The current file offset. */
+    KFOFF               offFile;
+    /** The file size. */
+    KFOFF               cbFile;
+    /** The offset of the buffer. */
+    KFOFF               offBuf;
+    /** The offset of the end of the buffer. */
+    KFOFF               offBufEnd;
+    /** The number of valid buffer bytes. */
+    KSIZE               cbBufValid;
+    /** The size of the buffer. */
+    KSIZE               cbBuf;
+    /** The buffer. */
+    KU8                *pbBuf;
+    /** Whether the pRdr instance should be closed together with us or not. */
+    KBOOL               fCloseIt;
+    /** Set if the buffer has been messed up by kRdrBufLineQ. */
+    KBOOL               fTainedByLineQ;
+} KRDRBUF, *PKRDRBUF;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static void     krdrBufDone(PKRDR pRdr);
+static int      krdrBufUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrBufProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
+static int      krdrBufRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrBufMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
+static KSIZE    krdrBufPageSize(PKRDR pRdr);
+static const char *krdrBufName(PKRDR pRdr);
+static KIPTR    krdrBufNativeFH(PKRDR pRdr);
+static KFOFF    krdrBufTell(PKRDR pRdr);
+static KFOFF    krdrBufSize(PKRDR pRdr);
+static int      krdrBufAllUnmap(PKRDR pRdr, const void *pvBits);
+static int      krdrBufAllMap(PKRDR pRdr, const void **ppvBits);
+static int      krdrBufRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
+static int      krdrBufDestroy(PKRDR pRdr);
+static int      krdrBufCreate(PPKRDR ppRdr, const char *pszFilename);
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** Native file provider operations.
+ *
+ * @remark  This is not in the file provider list as its intended for wrapping
+ *          other kRdr instances.
+ */
+static const KRDROPS g_krdrBufOps =
+{
+    "Buffered kRdr",
+    NULL,
+    krdrBufCreate,
+    krdrBufDestroy,
+    krdrBufRead,
+    krdrBufAllMap,
+    krdrBufAllUnmap,
+    krdrBufSize,
+    krdrBufTell,
+    krdrBufName,
+    krdrBufNativeFH,
+    krdrBufPageSize,
+    krdrBufMap,
+    krdrBufRefresh,
+    krdrBufProtect,
+    krdrBufUnmap,
+    krdrBufDone,
+    42
+};
+
+
+/** @copydoc KRDROPS::pfnDone */
+static void     krdrBufDone(PKRDR pRdr)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnDone(pThis->pRdr);
+}
+
+
+/** @copydoc KRDROPS::pfnUnmap */
+static int      krdrBufUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnUnmap(pThis->pRdr, pvBase, cSegments, paSegments);
+}
+
+
+/** @copydoc KRDROPS::pfnProtect */
+static int      krdrBufProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnProtect(pThis->pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect);
+}
+
+
+/** @copydoc KRDROPS::pfnRefresh */
+static int krdrBufRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnRefresh(pThis->pRdr, pvBase, cSegments, paSegments);
+}
+
+
+/** @copydoc KRDROPS::pfnMap */
+static int krdrBufMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnMap(pThis->pRdr, ppvBase, cSegments, paSegments, fFixed);
+}
+
+
+/** @copydoc KRDROPS::pfnPageSize */
+static KSIZE krdrBufPageSize(PKRDR pRdr)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnPageSize(pThis->pRdr);
+}
+
+
+/** @copydoc KRDROPS::pfnName */
+static const char *krdrBufName(PKRDR pRdr)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnName(pThis->pRdr);
+}
+
+
+/** @copydoc KRDROPS::pfnNativeFH */
+static KIPTR krdrBufNativeFH(PKRDR pRdr)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnNativeFH(pThis->pRdr);
+}
+
+
+/** @copydoc KRDROPS::pfnTell */
+static KFOFF krdrBufTell(PKRDR pRdr)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->offFile;
+}
+
+
+/** @copydoc KRDROPS::pfnSize */
+static KFOFF krdrBufSize(PKRDR pRdr)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->cbFile;
+}
+
+
+/** @copydoc KRDROPS::pfnAllUnmap */
+static int krdrBufAllUnmap(PKRDR pRdr, const void *pvBits)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnAllUnmap(pThis->pRdr, pvBits);
+}
+
+
+/** @copydoc KRDROPS::pfnAllMap */
+static int krdrBufAllMap(PKRDR pRdr, const void **ppvBits)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    return pThis->pRdr->pOps->pfnAllMap(pThis->pRdr, ppvBits);
+}
+
+
+/**
+ * Fills the buffer with file bits starting at the specified offset.
+ *
+ * @returns 0 on success, pfnRead error code on failure.
+ * @param   pThis   The instance.
+ * @param   off     Where to start reading.
+ */
+static int krdrBufFillBuffer(PKRDRBUF pThis, KFOFF off)
+{
+    kRdrAssert(off < pThis->cbFile);
+
+    /* Reposition the buffer if it's past the end of the file so that
+       we maximize its usability. We leave one unused byte at the end
+       of the buffer so kRdrBufLineQ can terminate its string properly.
+       Of course, this might end up re-reading a lot of stuff for no
+       future gain, but whatever... */
+    kRdrAssert(pThis->cbBuf <= pThis->cbFile + 1);
+    KFOFF cbLeft = pThis->cbFile - off;
+    KSIZE cbRead = pThis->cbBuf;
+    if ((KSSIZE)cbRead - 1 >= cbLeft)
+    {
+        cbRead--;
+        off = pThis->cbFile - cbRead;
+    }
+    int rc = pThis->pRdr->pOps->pfnRead(pThis->pRdr, pThis->pbBuf, cbRead, off);
+    if (!rc)
+    {
+        pThis->offBuf = off;
+        pThis->offBufEnd = off + cbRead;
+        pThis->cbBufValid = cbRead;
+    }
+    else
+    {
+        pThis->offBuf = pThis->offBufEnd = 0;
+        pThis->cbBufValid = 0;
+    }
+    pThis->fTainedByLineQ = K_FALSE;
+    return rc;
+}
+
+
+/** @copydoc KRDROPS::pfnRead */
+static int krdrBufRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+
+    /*
+     * We need to validate and update the file offset before
+     * we start making partial reads from the buffer and stuff.
+     */
+    KFOFF offEnd = off + cb;
+    if (    off >= pThis->cbFile
+        ||  offEnd > pThis->cbFile
+        ||  offEnd < off)
+        return KERR_OUT_OF_RANGE; /* includes EOF. */
+    pThis->offFile = offEnd;
+    if (!cb)
+        return 0;
+
+    /*
+     * Scratch the buffer if kRdrBufLineQ has tained it.
+     */
+    if (pThis->fTainedByLineQ)
+    {
+        pThis->offBuf = pThis->offBufEnd = 0;
+        pThis->cbBufValid = 0;
+    }
+
+    /*
+     * Is any part of the request in the buffer?
+     *
+     * We will currently ignore buffer hits in the middle of the
+     * request because it's annoying to implement and it's
+     * questionable whether it'll benefit much performance wise.
+     */
+    if (pThis->cbBufValid > 0)
+    {
+        if (off >= pThis->offBuf)
+        {
+            if (off < pThis->offBufEnd)
+            {
+                /* head (or all) of the request is in the buffer. */
+                KSIZE cbMaxChunk = (KSIZE)(pThis->offBufEnd - off);
+                KSIZE cbChunk = K_MIN(cb, cbMaxChunk);
+                kHlpMemCopy(pvBuf, &pThis->pbBuf[off - pThis->offBuf], cbChunk);
+                if (cbChunk == cb)
+                    return 0;
+
+                cb -= cbChunk;
+                pvBuf = (KU8 *)pvBuf + cbChunk;
+                off += cbChunk;
+            }
+        }
+        else if (   offEnd > pThis->offBuf
+                 && offEnd <= pThis->offBufEnd)
+        {
+            /* the end of the request is in the buffer. */
+            KSIZE cbChunk = (KSIZE)(pThis->offBufEnd - (offEnd));
+            kHlpMemCopy((KU8 *)pvBuf + (pThis->offBuf - off), pThis->pbBuf, cbChunk);
+            kRdrAssert(cbChunk < cb);
+            cb -= cbChunk;
+            offEnd -= cbChunk;
+        }
+    }
+
+    /*
+     * If the buffer is larger than the read request, read a full buffer
+     * starting at the requested offset. Otherwise perform an unbuffered
+     * read.
+     */
+    if (pThis->cbBuf > cb)
+    {
+        int rc = krdrBufFillBuffer(pThis, off);
+        if (rc)
+            return rc;
+        if (pThis->offBuf == off)
+            kHlpMemCopy(pvBuf, pThis->pbBuf, cb);
+        else
+        {
+            kRdrAssert(off > pThis->offBuf);
+            kRdrAssert(off + cb <= pThis->offBufEnd);
+            kHlpMemCopy(pvBuf, pThis->pbBuf + (off - pThis->offBuf), cb);
+        }
+    }
+    else
+    {
+        int rc = pThis->pRdr->pOps->pfnRead(pThis->pRdr, pvBuf, cb, off);
+        if (rc)
+            return rc;
+    }
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnDestroy */
+static int krdrBufDestroy(PKRDR pRdr)
+{
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+
+    /* Close the kRdr instance that we're wrapping. */
+    if (pThis->fCloseIt)
+    {
+        int rc = pThis->pRdr->pOps->pfnDestroy(pThis->pRdr);
+        if (rc)
+            return rc;
+        pThis->fCloseIt = K_FALSE;
+        pThis->pRdr = NULL;
+    }
+
+    kHlpFree(pThis->pbBuf);
+    pThis->pbBuf = NULL;
+    kHlpFree(pRdr);
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnCreate */
+static int krdrBufCreate(PPKRDR ppRdr, const char *pszFilename)
+{
+    return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * Worker for kRdrBufOpen and kRdrBufWrap.
+ *
+ * It's essentially kRdrBufWrap without error checking.
+ *
+ * @returns 0 on success, one of the kErrors status code on failure.
+ * @param   ppRdr           Where to store the new file provider instance.
+ * @param   pRdrWrapped     The file provider instance to buffer.
+ * @param   fCloseIt        Whether it the pRdrWrapped instance should be closed
+ *                          when the new instance is closed.
+ */
+static int krdrBufWrapIt(PPKRDR ppRdr, PKRDR pRdrWrapped, KBOOL fCloseIt)
+{
+    PKRDRBUF pThis = (PKRDRBUF)kHlpAlloc(sizeof(*pThis));
+    if (pThis)
+    {
+        pThis->Core.u32Magic = KRDR_MAGIC;
+        pThis->Core.pOps = &g_krdrBufOps;
+        pThis->pRdr = pRdrWrapped;
+        pThis->offFile = pRdrWrapped->pOps->pfnTell(pRdrWrapped);
+        pThis->cbFile = pRdrWrapped->pOps->pfnSize(pRdrWrapped);
+        pThis->offBuf = pThis->offBufEnd = 0;
+        pThis->cbBufValid = 0;
+        pThis->fCloseIt = fCloseIt;
+        pThis->fTainedByLineQ = K_FALSE;
+        if (pThis->cbFile < 128*1024)
+            pThis->cbBuf = (KSIZE)pThis->cbFile + 1; /* need space for the kRdrBufLineQ terminator. */
+        else
+            pThis->cbBuf = 64*1024;
+        pThis->pbBuf = (KU8 *)kHlpAlloc(pThis->cbBuf);
+        if (pThis->pbBuf)
+        {
+            *ppRdr = &pThis->Core;
+            return 0;
+        }
+
+        pThis->Core.u32Magic = 0;
+        kHlpFree(pThis);
+    }
+    return KERR_NO_MEMORY;
+}
+
+
+/**
+ * Opens a file provider with a buffered wrapper.
+ *
+ * @returns 0 on success, KERR_* on failure.
+ * @param   ppRdr       Where to store the buffered file reader instance on success.
+ * @param   pszFilename The name of the file that should be opened.
+ */
+KRDR_DECL(int) kRdrBufOpen(PPKRDR ppRdr, const char *pszFilename)
+{
+    kRdrAssertPtrReturn(ppRdr, KERR_INVALID_POINTER);
+    *ppRdr = NULL;
+
+    PKRDR pRdrWrapped;
+    int rc = kRdrOpen(&pRdrWrapped, pszFilename);
+    if (!rc)
+    {
+        rc = krdrBufWrapIt(ppRdr, pRdrWrapped, K_TRUE);
+        if (rc)
+            kRdrClose(pRdrWrapped);
+    }
+    return rc;
+}
+
+
+/**
+ * Creates a buffered file provider instance for an existing one.
+ *
+ * @returns 0 on success, KERR_* on failure.
+ * @param   ppRdr           Where to store the new file provider pointer.
+ * @param   pRdr            The file provider instance to wrap.
+ * @param   fCLoseIt        Whether it the wrapped reader should be automatically
+ *                          closed when the wrapper closes.
+ */
+KRDR_DECL(int) kRdrBufWrap(PPKRDR ppRdr, PKRDR pRdr, KBOOL fCloseIt)
+{
+    KRDR_VALIDATE(pRdr);
+    return krdrBufWrapIt(ppRdr, pRdr, fCloseIt);
+}
+
+
+/**
+ * Checks whether the file provider instance is of the buffered type or not.
+ *
+ * @returns K_TRUE if it is, otherwise K_FALSE.
+ * @param   pRdr            The file provider instance to check.
+ */
+KRDR_DECL(KBOOL) kRdrBufIsBuffered(PKRDR pRdr)
+{
+    KRDR_VALIDATE_EX(pRdr, K_FALSE);
+    return pRdr->pOps == &g_krdrBufOps;
+}
+
+
+/**
+ * Reads a line from a buffered file provider.
+ *
+ * The trailing '\n' or '\r\n' is stripped.
+ *
+ * @returns 0 on success. KERR_* on failure.
+ * @retval  KRDR_ERR_LINE_TOO_LONG if the line is too long to fit in the passed in buffer.
+ * @retval  KRDR_ERR_NOT_BUFFERED_RDR if pRdr isn't a buffered reader.
+ * @param   pRdr        The buffered file reader.
+ * @param   pszLine     Where to store the line.
+ * @param   cbLine      The size of the the line buffer.
+ */
+KRDR_DECL(int) kRdrBufLine(PKRDR pRdr, char *pszLine, KSIZE cbLine)
+{
+    return kRdrBufLineEx(pRdr, pszLine, &cbLine);
+}
+
+
+/**
+ * Reads a line from a buffered file provider.
+ *
+ * The trailing '\n' or '\r\n' is stripped.
+ *
+ * @returns 0 on success. KERR_* on failure.
+ * @retval  KRDR_ERR_LINE_TOO_LONG if the line is too long to fit in the passed in buffer.
+ * @retval  KRDR_ERR_NOT_BUFFERED_RDR if pRdr isn't a buffered reader.
+ * @param   pRdr        The buffered file reader.
+ * @param   pszLine     Where to store the line.
+ * @param   pcbLine     The size of the the line buffer on input, the length of the
+ *                      returned line on output.
+ */
+KRDR_DECL(int) kRdrBufLineEx(PKRDR pRdr, char *pszLine, KSIZE *pcbLine)
+{
+    /*
+     * Validate input.
+     */
+    kRdrAssertPtrReturn(pcbLine, KERR_INVALID_POINTER);
+    KSIZE cbLeft = *pcbLine;
+    *pcbLine = 0;
+    kRdrAssertReturn(cbLeft > 0, KERR_INVALID_PARAMETER);
+    KRDR_VALIDATE(pRdr);
+    kRdrAssertReturn(pRdr->pOps != &g_krdrBufOps, KRDR_ERR_NOT_BUFFERED_RDR);
+    kRdrAssertPtrReturn(pszLine, KERR_INVALID_POINTER);
+
+    /* check for EOF */
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    if (pThis->offFile >= pThis->cbFile)
+    {
+        kRdrAssert(pThis->offFile == pThis->cbFile);
+        *pszLine = '\0';
+        *pcbLine = 0;
+        return KERR_EOF;
+    }
+
+    /*
+     * Scratch the buffer if kRdrBufLineQ has tained it.
+     */
+    if (pThis->fTainedByLineQ)
+    {
+        pThis->offBuf = pThis->offBufEnd = 0;
+        pThis->cbBufValid = 0;
+    }
+
+    /*
+     * Buffered read loop.
+     *
+     * The overflow logic is a bit fishy wrt to overflowing at an "\r\n"
+     * that arrives at a buffer boundrary. The current policy is to try
+     * our best to not to fail with overflow in the EOL sequence or EOF.
+     * If it's the end of the buffer, it will not be refilled just to
+     * check for this because that's too much work.
+     */
+    cbLeft--; /* reserve space for the terminator. */
+    char *pszOut = pszLine;
+    for (;;)
+    {
+        /*
+         * Do we need to (re-)fill the buffer or does it contain something
+         * that we can work on already?
+         */
+        if (    !pThis->cbBufValid
+            ||  pThis->offFile >= pThis->offBufEnd
+            ||  pThis->offFile < pThis->offBuf)
+        {
+            int rc = krdrBufFillBuffer(pThis, pThis->offFile);
+            if (rc)
+            {
+                *pszOut = '\0';
+                return rc;
+            }
+        }
+
+        /*
+         * Parse the buffer looking for the EOL indicator.
+         */
+        kRdrAssert(pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd);
+        kRdrAssert(sizeof(char) == sizeof(*pThis->pbBuf));
+        const char * const pszStart = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf];
+        const char * const pszEnd   = (const char *)&pThis->pbBuf[pThis->cbBufValid];
+        const char *psz = pszStart;
+        while (psz < pszEnd)
+        {
+            const char ch = *psz;
+            if (ch == '\n')
+            {
+                /* found the EOL, update file position and line length. */
+                pThis->offFile += psz - pszStart + 1;
+                *pcbLine += psz - pszStart;
+
+                /* terminate the string, checking for "\r\n" first. */
+                if (    *pcbLine
+                    &&  pszOut[-1] == '\r')
+                {
+                    *pcbLine -= 1;
+                    pszOut--;
+                }
+                *pszOut = '\0';
+                return 0;
+            }
+            if (!cbLeft)
+            {
+                /* the line is *probably* too long. */
+                pThis->offFile += psz - pszStart;
+                *pcbLine += psz - pszStart;
+                *pszOut = '\0';
+
+                /* The only possible case where the line actually isn't too long
+                   is if we're at a "\r\n" sequence. We will re-fill the buffer
+                   if necessary to check for the '\n' as it's not that much work. */
+                if (    ch == '\r'
+                    &&  pThis->offFile + 2 <= pThis->cbFile)
+                {
+                    if (psz + 1 >= pszEnd)
+                    {
+                        int rc = krdrBufFillBuffer(pThis, pThis->offFile);
+                        if (rc)
+                        {
+                            *pszOut = '\0';
+                            return rc;
+                        }
+                    }
+                    psz = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf];
+                    kRdrAssert(*psz == '\r');
+                    if (psz[1] == '\n')
+                    {
+                        *pcbLine -= 1;
+                        pszOut[-1] = '\0';
+                        pThis->offFile += 2;
+                        return 0;
+                    }
+                }
+                return KRDR_ERR_LINE_TOO_LONG;
+            }
+
+            /* copy and advance */
+            *pszOut++ = ch;
+            cbLeft--;
+            psz++;
+        }
+
+        /* advance past the buffer and check for EOF. */
+        *pcbLine += pszEnd - pszStart;
+        pThis->offFile = pThis->offBufEnd;
+        if (pThis->offFile >= pThis->cbFile)
+        {
+            kRdrAssert(pThis->offFile == pThis->cbFile);
+            *pszOut = '\0';
+            return 0;
+        }
+    }
+    return -1;
+}
+
+
+/**
+ * Worker for kRdrBufLineQ that searches the current buffer for EOL or EOF.
+ *
+ * When a EOF marker is found
+ *
+ *
+ * @returns NULL if EOL/EOF isn't found the buffer.
+ * @param   pThis   The buffered reader instance.
+ */
+static const char * krdrBufLineQWorker(PKRDRBUF pThis)
+{
+    kRdrAssert(pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd);
+
+    /*
+     * Search the buffer.
+     */
+    kRdrAssert(sizeof(char) == sizeof(*pThis->pbBuf));
+    const char * const pszStart = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf];
+    const char * const pszEnd   = (const char *)&pThis->pbBuf[pThis->cbBufValid];
+    char *psz = (char *)pszStart;
+    while (psz < pszEnd)
+    {
+        char ch = *psz;
+        if (ch == '\n')
+        {
+            pThis->offFile += psz - pszStart;
+            pThis->fTainedByLineQ = K_TRUE;
+            *psz = '\0';
+            if (    psz > pszStart
+                &&  psz[-1] == '\r')
+                *--psz = '\0';
+            return pszStart;
+        }
+        psz++;
+    }
+
+    /*
+     * Check for EOF. There must be room for a terminator char here.
+     */
+    if (    pThis->offBufEnd >= pThis->cbFile
+        &&  (pThis->offBufEnd - pThis->offBuf) < (KSSIZE)pThis->cbBuf)
+    {
+        pThis->offFile = pThis->cbFile;
+        pThis->pbBuf[pThis->cbBufValid] = '\0';
+        return pszStart;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Get the pointer to the next next line in the buffer.
+ * The returned line is zero terminated.
+ *
+ * @returns A pointer to the line on success. This becomes invalid
+ *          upon the next call to this kRdr instance.
+ * @returns NULL on EOF, read error of if the line was too long.
+ * @param   pRdr        The buffered file reader.
+ */
+KRDR_DECL(const char *) kRdrBufLineQ(PKRDR pRdr)
+{
+    /*
+     * Validate input.
+     */
+    KRDR_VALIDATE_EX(pRdr, NULL);
+    kRdrAssertReturn(pRdr->pOps != &g_krdrBufOps, NULL);
+
+    /* check for EOF */
+    PKRDRBUF pThis = (PKRDRBUF)pRdr;
+    if (pThis->offFile >= pThis->cbFile)
+    {
+        kRdrAssert(pThis->offFile == pThis->cbFile);
+        return NULL;
+    }
+
+    /*
+     * Search the current buffer if possible
+     */
+    if (    pThis->cbBufValid
+        &&  pThis->offFile >= pThis->offBuf
+        &&  pThis->offFile < pThis->offBufEnd)
+    {
+        const char *psz = krdrBufLineQWorker(pThis);
+        if (psz)
+            return psz;
+    }
+
+    /*
+     * Fill the buffer in an optimal way and look for the EOL/EOF (again).
+     */
+    int rc = krdrBufFillBuffer(pThis, pThis->offFile);
+    if (rc)
+        return NULL;
+    return krdrBufLineQWorker(pThis);
+}
+
Index: /trunk/kRdr/kRdrFile.cpp
===================================================================
--- /trunk/kRdr/kRdrFile.cpp	(revision 2)
+++ /trunk/kRdr/kRdrFile.cpp	(revision 2)
@@ -0,0 +1,1309 @@
+/* $Id$ */
+/** @file
+ * kRdrFile - The Native File Provider
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kRdrInternal.h"
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+#include <k/kErrors.h>
+
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+# include <k/kHlpSys.h>
+# include <sys/fcntl.h>
+# include <sys/mman.h>
+# include <unistd.h>
+
+#elif K_OS == K_OS_OS2
+# define INCL_ERRORS
+# define INCL_BASE
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# define WIN32_NO_STATUS
+# include <Windows.h>
+# include <ntsecapi.h>
+# include <ntstatus.h>
+
+# ifdef __cplusplus
+  extern "C" {
+# endif
+
+  /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */
+  typedef LONG NTSTATUS;
+  #define NT_SUCCESS(x) ((x)>=0)
+
+  typedef struct _OBJECT_ATTRIBUTES
+  {
+      ULONG   Length;
+      HANDLE  RootDirectory;
+      PUNICODE_STRING ObjectName;
+      ULONG   Attributes;
+      PVOID   SecurityDescriptor;
+      PVOID   SecurityQualityOfService;
+  } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
+
+  typedef enum _SECTION_INHERIT
+  {
+      ViewShare = 1,
+      ViewUnmap = 2
+  } SECTION_INHERIT;
+
+# define NTOSAPI __declspec(dllimport)
+# define NtCurrentProcess() GetCurrentProcess()
+
+# ifndef MEM_DOS_LIM
+#  define MEM_DOS_LIM 0x40000000UL
+# endif
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtCreateSection(
+      OUT PHANDLE SectionHandle,
+      IN ACCESS_MASK DesiredAccess,
+      IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+      IN PLARGE_INTEGER SectionSize OPTIONAL,
+      IN ULONG Protect,
+      IN ULONG Attributes,
+      IN HANDLE FileHandle OPTIONAL
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtMapViewOfSection(
+      IN HANDLE SectionHandle,
+      IN HANDLE ProcessHandle,
+      IN OUT PVOID *BaseAddress,
+      IN ULONG ZeroBits,
+      IN ULONG CommitSize,
+      IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
+      IN OUT PSIZE_T ViewSize,
+      IN SECTION_INHERIT InheritDisposition,
+      IN ULONG AllocationType,
+      IN ULONG Protect
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtUnmapViewOfSection(
+      IN HANDLE ProcessHandle,
+      IN PVOID BaseAddress
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtClose(
+      IN HANDLE Handle
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  ZwProtectVirtualMemory(
+      IN HANDLE ProcessHandle,
+      IN OUT PVOID *BaseAddress,
+      IN OUT PSIZE_T ProtectSize,
+      IN ULONG NewProtect,
+      OUT PULONG OldProtect
+  );
+# define NtProtectVirtualMemory ZwProtectVirtualMemory
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtAllocateVirtualMemory(
+      IN HANDLE ProcessHandle,
+      IN OUT PVOID *BaseAddress,
+      IN ULONG ZeroBits,
+      IN OUT PSIZE_T AllocationSize,
+      IN ULONG AllocationType,
+      IN ULONG Protect
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtFreeVirtualMemory(
+      IN HANDLE ProcessHandle,
+      IN OUT PVOID *BaseAddress,
+      IN OUT PSIZE_T FreeSize,
+      IN ULONG FreeType
+  );
+
+# ifdef __cplusplus
+  }
+# endif
+
+#else
+# error "port me"
+#endif
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Prepared stuff.
+ */
+typedef struct KRDRFILEPREP
+{
+    /** The address of the prepared region. */
+    void           *pv;
+    /** The size of the prepared region. */
+    KSIZE           cb;
+#if K_OS == K_OS_WINDOWS
+    /** Handle to the section created to map the file. */
+    HANDLE          hSection;
+#endif
+} KRDRFILEPREP, *PKRDRFILEPREP;
+
+/**
+ * The file provier instance for native files.
+ */
+typedef struct KRDRFILE
+{
+    /** The file reader vtable. */
+    KRDR                Core;
+    /** The file handle. */
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    int                 File;
+#elif K_OS == K_OS_OS2
+    HFILE               File;
+#elif K_OS == K_OS_WINDOWS
+    HANDLE              File;
+#else
+# error "Port me!"
+#endif
+    /** The current file offset. */
+    KFOFF               off;
+    /** The file size. */
+    KFOFF               cb;
+    /** Array where we stuff the mapping area data. */
+    KRDRFILEPREP        aPreps[4];
+    /** The number of current preps. */
+    KU32                cPreps;
+    /** Number of mapping references. */
+    KI32                cMappings;
+    /** The memory mapping. */
+    void               *pvMapping;
+    /** The filename. */
+    char                szFilename[1];
+} KRDRFILE, *PKRDRFILE;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static void     krdrFileDone(PKRDR pRdr);
+static int      krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
+static int      krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
+static int      krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
+static int      krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
+static KSIZE   krdrFilePageSize(PKRDR pRdr);
+static const char *krdrFileName(PKRDR pRdr);
+static KIPTR    krdrFileNativeFH(PKRDR pRdr);
+static KFOFF    krdrFileTell(PKRDR pRdr);
+static KFOFF    krdrFileSize(PKRDR pRdr);
+static int      krdrFileAllUnmap(PKRDR pRdr, const void *pvBits);
+static int      krdrFileAllMap(PKRDR pRdr, const void **ppvBits);
+static int      krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
+static int      krdrFileDestroy(PKRDR pRdr);
+static int      krdrFileCreate(PPKRDR ppRdr, const char *pszFilename);
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** Native file provider operations. */
+const KRDROPS g_kRdrFileOps =
+{
+    "native file",
+    NULL,
+    krdrFileCreate,
+    krdrFileDestroy,
+    krdrFileRead,
+    krdrFileAllMap,
+    krdrFileAllUnmap,
+    krdrFileSize,
+    krdrFileTell,
+    krdrFileName,
+    krdrFileNativeFH,
+    krdrFilePageSize,
+    krdrFileMap,
+    krdrFileRefresh,
+    krdrFileProtect,
+    krdrFileUnmap,
+    krdrFileDone,
+    42
+};
+
+
+#if K_OS == K_OS_WINDOWS
+/**
+ * Converts a kLdr segment protection to NT protection for a mapping.
+ *
+ * @returns Nt page protection.
+ * @param   enmProt     kLdr protection.
+ */
+static ULONG krdrFileGetNtMapProt(KPROT enmProt)
+{
+    switch (enmProt)
+    {
+        case KPROT_NOACCESS:             return PAGE_NOACCESS;
+        case KPROT_READONLY:             return PAGE_READONLY;
+        case KPROT_READWRITE:            return PAGE_READWRITE;
+        case KPROT_WRITECOPY:            return PAGE_WRITECOPY;
+        case KPROT_EXECUTE:              return PAGE_EXECUTE;
+        case KPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
+        case KPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
+        case KPROT_EXECUTE_WRITECOPY:    return PAGE_EXECUTE_WRITECOPY;
+        default:                            return ~(ULONG)0;
+    }
+}
+
+
+/**
+ * Converts a kLdr segment protection to NT protection for a allocation.
+ *
+ * @returns Nt page protection.
+ * @param   enmProt     kLdr protection.
+ */
+static ULONG krdrFileGetNtAllocProt(KPROT enmProt)
+{
+    switch (enmProt)
+    {
+        case KPROT_NOACCESS:             return PAGE_NOACCESS;
+        case KPROT_READONLY:             return PAGE_READONLY;
+        case KPROT_WRITECOPY:
+        case KPROT_READWRITE:            return PAGE_READWRITE;
+        case KPROT_EXECUTE:              return PAGE_EXECUTE;
+        case KPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
+        case KPROT_EXECUTE_WRITECOPY:
+        case KPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
+        default:                            return ~(ULONG)0;
+    }
+}
+#endif
+
+
+/** @copydoc KRDROPS::pfnDone */
+static void     krdrFileDone(PKRDR pRdr)
+{
+}
+
+
+/**
+ * Finds a prepared mapping region.
+ *
+ * @returns Pointer to the aPrep entry.
+ * @param   pFile   The instance data.
+ * @param   pv      The base of the region.
+ */
+static PKRDRFILEPREP krdrFileFindPrepExact(PKRDRFILE pFile, void *pv)
+{
+    KI32 i = pFile->cPreps;
+    while (i-- > 0)
+        if (pFile->aPreps[i].pv == pv)
+            return &pFile->aPreps[i];
+    return NULL;
+}
+
+
+/** @copydoc KRDROPS::pfnUnmap */
+static int      krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
+    PKRDRFILEPREP       pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
+    int                 rc;
+    if (!pPrep)
+        return KERR_INVALID_PARAMETER;
+
+#if K_OS == K_OS_WINDOWS
+    if (pPrep->hSection != NULL)
+    {
+        /** @todo implement me. */
+        return -1;
+    }
+#endif
+
+    rc = krdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
+
+    /* remove the mapping data on success. */
+    if (!rc)
+    {
+        pRdrFile->cPreps--;
+        if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
+            *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
+    }
+    return rc;
+}
+
+
+/** Generic implementation of krdrFileUnmap. */
+static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
+    return kHlpPageFree(pPrep->pv, pPrep->cb);
+}
+
+
+/** @copydoc KRDROPS::pfnProtect */
+static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
+{
+    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
+    PKRDRFILEPREP    pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
+    if (!pPrep)
+        return KERR_INVALID_PARAMETER;
+
+#if K_OS == K_OS_WINDOWS
+    if (pPrep->hSection != NULL)
+    {
+        /** @todo implement me. */
+        return -1;
+    }
+#endif
+
+    return krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
+}
+
+
+/** Generic implementation of krdrFileProtect. */
+static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
+{
+    KU32 i;
+
+    /*
+     * Iterate the segments and apply memory protection changes.
+     */
+    for (i = 0; i < cSegments; i++)
+    {
+        int rc;
+        void *pv;
+        KPROT enmProt;
+
+        if (paSegments[i].RVA == NIL_KLDRADDR)
+            continue;
+
+        /* calc new protection. */
+        enmProt = (KPROT)paSegments[i].enmProt; /** @todo drop cast */
+        if (fUnprotectOrProtect)
+        {
+            switch (enmProt)
+            {
+                case KPROT_NOACCESS:
+                case KPROT_READONLY:
+                case KPROT_READWRITE:
+                case KPROT_WRITECOPY:
+                    enmProt = KPROT_READWRITE;
+                    break;
+                case KPROT_EXECUTE:
+                case KPROT_EXECUTE_READ:
+                case KPROT_EXECUTE_READWRITE:
+                case KPROT_EXECUTE_WRITECOPY:
+                    enmProt = KPROT_EXECUTE_READWRITE;
+                    break;
+                default:
+                    kRdrAssert(!"bad enmProt");
+                    return -1;
+            }
+        }
+        else
+        {
+            /* copy on write -> normal write. */
+            if (enmProt == KPROT_EXECUTE_WRITECOPY)
+                enmProt = KPROT_EXECUTE_READWRITE;
+            else if (enmProt == KPROT_WRITECOPY)
+                enmProt = KPROT_READWRITE;
+        }
+
+        pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
+
+        rc = kHlpPageProtect(pv, paSegments[i].cbMapped, enmProt);
+        if (rc)
+            break;
+    }
+
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnRefresh */
+static int      krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
+    PKRDRFILEPREP    pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
+    if (!pPrep)
+        return KERR_INVALID_PARAMETER;
+
+#if K_OS == K_OS_WINDOWS
+    if (pPrep->hSection != NULL)
+    {
+        /** @todo implement me. */
+        return -1;
+    }
+#endif
+
+    return krdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
+}
+
+
+/** Generic implementation of krdrFileRefresh. */
+static int      krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    int rc;
+    int rc2;
+    KU32 i;
+
+    /*
+     * Make everything writable again.
+     */
+    rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
+    if (rc)
+    {
+        krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
+        return rc;
+    }
+
+    /*
+     * Clear everything.
+     */
+    /** @todo only zero the areas not covered by raw file bits. */
+    kHlpMemSet(pPrep->pv, 0, pPrep->cb);
+
+    /*
+     * Reload all the segments.
+     * We could possibly skip some segments, but we currently have
+     * no generic way of figuring out which at the moment.
+     */
+    for (i = 0; i < cSegments; i++)
+    {
+        void *pv;
+
+        if (    paSegments[i].RVA == NIL_KLDRADDR
+            ||  paSegments[i].cbFile <= 0)
+            continue;
+
+        pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
+        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
+        if (rc)
+            break;
+    }
+
+    /*
+     * Protect the bits again.
+     */
+    rc2 = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
+    if (rc2 && rc)
+        rc = rc2;
+
+    return rc;
+}
+
+
+/** @copydoc KRDROPS::pfnMap */
+static int      krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
+{
+    PKRDRFILE       pRdrFile = (PKRDRFILE)pRdr;
+    PKRDRFILEPREP   pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
+    KLDRSIZE        cbTotal;
+    const KSIZE     cbPage = pRdr->pOps->pfnPageSize(pRdr);
+    int             rc;
+    KU32            i;
+
+    if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps))
+        return KRDR_ERR_TOO_MANY_MAPPINGS;
+
+    /*
+     * Calc the total mapping space needed.
+     */
+    cbTotal = 0;
+    for (i = 0; i < cSegments; i++)
+    {
+        KLDRSIZE uRVASegmentEnd;
+        if (paSegments[i].RVA == NIL_KLDRADDR)
+            continue;
+        uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
+        if (cbTotal < uRVASegmentEnd)
+            cbTotal = uRVASegmentEnd;
+    }
+    pPrep->cb = (KSIZE)cbTotal;
+    if (pPrep->cb != cbTotal)
+        return KLDR_ERR_ADDRESS_OVERFLOW;
+    pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
+
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    /** @todo */
+
+#elif K_OS == K_OS_WINDOWS
+    /*
+     * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
+     * trying to map a PE image and the kernel can parse the file for it self, the
+     * API just isn't up to scratch.
+     *
+     * Problems:
+     *      1. Reserving memory for the views is risky because you can't reserve and
+     *         map into the reserved space. So, other threads might grab the memory
+     *         before we get to it.
+     *      2. The page aligning of file offsets makes it impossible to map most
+     *         executable images since these are commonly sector aligned.
+     *      3. When mapping a read+execute file, its not possible to create section
+     *         larger than the file since the section size is bound to the data file
+     *         size. This wouldn't have been such a problem if it was possible to
+     *         map views beyond the section restriction, i.e. have a file size and
+     *         view size.
+     *      4. Only x86 can map views at page granularity it seems, and that only
+     *         using an undocument flag. The default granularity is 64KB.
+     *      5. There is more crappyness here...
+     *
+     * So, first we'll have to check if we can the file using the crappy NT APIs.
+     * Chances are we can't.
+     */
+    for (i = 0; i < cSegments; i++)
+    {
+        if (paSegments[i].RVA == NIL_KLDRADDR)
+            continue;
+
+        /* The file backing of the segments must be page aligned. */
+        if (    paSegments[i].cbFile > 0
+            &&  paSegments[i].offFile & (cbPage - 1))
+            break;
+
+        /* Only page alignment gaps between the file size and the mapping size. */
+        if (    paSegments[i].cbFile > 0
+            &&  (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
+            break;
+
+        /* The mapping addresses of the segments must be page aligned.
+         * Non-x86 will probably require 64KB alignment here. */
+        if (paSegments[i].RVA & (cbPage - 1))
+            break;
+
+        /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
+        if (    paSegments[i].cbFile > 0
+            &&  (paSegments[i].RVA & 0xffff))
+            break;
+    }
+    /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */
+    if (i == cSegments)
+    {
+        /* WOW! it may work out! Incredible! */
+        SIZE_T          ViewSize;
+        LARGE_INTEGER   SectionOffset;
+        LARGE_INTEGER   MaxiumSize;
+        NTSTATUS        Status;
+        PVOID           pv;
+
+        MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
+        if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
+            MaxiumSize.QuadPart = cbTotal;
+
+        Status = NtCreateSection(&pPrep->hSection,
+                                 SECTION_MAP_EXECUTE | SECTION_MAP_READ,    /* desired access */
+                                 NULL,                                      /* object attributes */
+                                 &MaxiumSize,
+                                 PAGE_EXECUTE_WRITECOPY,                    /* page attributes */
+                                 SEC_COMMIT,                                /* section attributes */
+                                 pRdrFile->File);
+        if (!NT_SUCCESS(Status))
+            return (int)Status;
+
+        /*
+         * Determin the base address.
+         */
+        if (fFixed)
+            pPrep->pv = *ppvBase;
+        else
+        {
+            pv = NULL;
+            ViewSize = (KSIZE)cbTotal;
+
+            Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+                                             &pv,
+                                             0,                             /* ZeroBits */
+                                             &ViewSize,
+                                             MEM_RESERVE,
+                                             PAGE_READONLY);
+            if (NT_SUCCESS(Status))
+            {
+                pPrep->pv = *ppvBase = pv;
+                ViewSize = 0;
+                Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
+            }
+            if (!NT_SUCCESS(Status))
+            {
+                NtClose(pPrep->hSection);
+                return Status;
+            }
+        }
+
+        /*
+         * Map the segments.
+         */
+        for (i = 0; i < cSegments; i++)
+        {
+            ULONG fPageProt;
+
+            if (paSegments[i].RVA == NIL_KLDRADDR)
+                continue;
+
+            pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
+            if (paSegments[i].cbFile > 0)
+            {
+                SectionOffset.QuadPart = paSegments[i].offFile;
+                ViewSize = paSegments[i].cbFile;
+                fPageProt = krdrFileGetNtMapProt(paSegments[i].enmProt);
+                /* STATUS_MAPPED_ALIGNMENT
+                   STATUS_CONFLICTING_ADDRESSES
+                   STATUS_INVALID_VIEW_SIZE */
+                Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
+                                            &pv,
+                                            0,                                  /* ZeroBits */
+                                            0,                                  /* CommitSize */
+                                            &SectionOffset,                     /* SectionOffset */
+                                            &ViewSize,
+                                            ViewUnmap,
+                                            MEM_DOS_LIM,                        /* AllocationType */
+                                            fPageProt);
+                /* do we have to zero anything? */
+                if (    NT_SUCCESS(Status)
+                    &&  0/*later*/)
+                {
+                    /*ULONG OldPageProt = 0;
+                      NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */
+                }
+            }
+            else
+            {
+                ViewSize = paSegments[i].cbMapped;
+                fPageProt = krdrFileGetNtAllocProt(paSegments[i].enmProt);
+                Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+                                                 &pv,
+                                                 0,                             /* ZeroBits */
+                                                 &ViewSize,
+                                                 MEM_COMMIT,
+                                                 fPageProt);
+            }
+            if (!NT_SUCCESS(Status))
+                break;
+        }
+
+        /*
+         * On success, commit the mapping and return.
+         */
+        if (NT_SUCCESS(Status))
+        {
+            pRdrFile->cPreps++;
+            return 0;
+        }
+
+        /* bail out and fall back on the generic code. */
+        while (i-- > 0)
+        {
+            PVOID pv;
+
+            if (paSegments[i].RVA == NIL_KLDRADDR)
+                continue;
+
+            pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
+            if (paSegments[i].cbFile > 0)
+                NtUnmapViewOfSection(NtCurrentProcess(), pv);
+            else
+                NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
+        }
+        NtClose(pPrep->hSection);
+    }
+    /* else: fall back to the generic code */
+    pPrep->hSection = NULL;
+#endif
+
+    /*
+     * Use the generic map emulation.
+     */
+    pPrep->pv = fFixed ? *ppvBase : NULL;
+    rc = krdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
+    if (!rc)
+    {
+        *ppvBase = pPrep->pv;
+        pRdrFile->cPreps++;
+    }
+
+    return rc;
+}
+
+
+/** Generic implementation of krdrFileMap. */
+static int  krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
+{
+    int rc;
+    KU32 i;
+
+    /*
+     * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect().
+     */
+    rc = kHlpPageAlloc(&pPrep->pv, pPrep->cb, KPROT_EXECUTE_READWRITE, fFixed);
+    if (rc)
+        return rc;
+
+    /*
+     * Load the data.
+     */
+    for (i = 0; i < cSegments; i++)
+    {
+        void *pv;
+
+        if (    paSegments[i].RVA == NIL_KLDRADDR
+            ||  paSegments[i].cbFile <= 0)
+            continue;
+
+        pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
+        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
+        if (rc)
+            break;
+    }
+
+    /*
+     * Set segment protection.
+     */
+    if (!rc)
+    {
+        rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
+        if (!rc)
+            return 0;
+        krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
+    }
+
+    /* bailout */
+    kHlpPageFree(pPrep->pv, pPrep->cb);
+    return rc;
+}
+
+
+/** @copydoc KRDROPS::pfnPageSize */
+static KSIZE   krdrFilePageSize(PKRDR pRdr)
+{
+#if K_OS == K_OS_DARWIN
+    return 0x1000; /** @todo find some header somewhere... */
+
+#elif K_OS == K_OS_LINUX
+    return 0x1000; /** @todo find some header somewhere... */
+
+#elif K_OS == K_OS_OS2
+    /* The page size on OS/2 wont change anytime soon. :-) */
+    return 0x1000;
+
+#elif K_OS == K_OS_WINDOWS
+    SYSTEM_INFO SysInfo;
+    GetSystemInfo(&SysInfo);
+    return SysInfo.dwPageSize;
+    /*return SysInfo.dwAllocationGranularity;*/
+#else
+# error "port me"
+#endif
+}
+
+
+/** @copydoc KRDROPS::pfnName */
+static const char *krdrFileName(PKRDR pRdr)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+    return &pRdrFile->szFilename[0];
+}
+
+
+static KIPTR krdrFileNativeFH(PKRDR pRdr)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_OS2 \
+ || K_OS == K_OS_SOLARIS \
+ || K_OS == K_OS_WINDOWS
+    return (KIPTR)pRdrFile->File;
+#else
+# error "port me"
+#endif
+}
+
+
+/** @copydoc KRDROPS::pfnTell */
+static KFOFF krdrFileTell(PKRDR pRdr)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+
+    /*
+     * If the offset is undefined, try figure out what it is.
+     */
+    if (pRdrFile->off == -1)
+    {
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+        pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_CUR, 0);
+        if (pRdrFile->off < 0)
+            pRdrFile->off = -1;
+
+#elif K_OS == K_OS_OS2
+        ULONG ulNew;
+        APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew);
+        if (rc)
+            return -1;
+        pRdrFile->off = ulNew;
+
+#elif K_OS == K_OS_WINDOWS
+        LONG offHigh = 0;
+        LONG offLow;
+        int rc;
+
+        SetLastError(0);
+        offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
+        rc = GetLastError();
+        if (rc)
+            return -1;
+        pRdrFile->off = ((KFOFF)offHigh << 32) | offLow;
+
+#else
+# error "port me."
+#endif
+    }
+    return pRdrFile->off;
+}
+
+
+/** @copydoc KRDROPS::pfnSize */
+static KFOFF krdrFileSize(PKRDR pRdr)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+    return pRdrFile->cb;
+}
+
+
+/** @copydoc KRDROPS::pfnAllUnmap */
+static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+
+    /* check for underflow */
+    if (pRdrFile->cMappings <= 0)
+        return KERR_INVALID_PARAMETER;
+
+    /* decrement usage counter, free mapping if no longer in use. */
+    if (!--pRdrFile->cMappings)
+    {
+        kHlpFree(pRdrFile->pvMapping);
+        pRdrFile->pvMapping = NULL;
+    }
+
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnAllMap */
+static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+
+    /*
+     * Do we need to map it?
+     */
+    if (!pRdrFile->pvMapping)
+    {
+        int rc;
+        KFOFF cbFile = pRdrFile->Core.pOps->pfnSize(pRdr);
+        KSIZE cb = (KSIZE)cbFile;
+        if (cb != cbFile)
+            return KERR_NO_MEMORY;
+
+        pRdrFile->pvMapping = kHlpAlloc(cb);
+        if (!pRdrFile->pvMapping)
+            return KERR_NO_MEMORY;
+        rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0);
+        if (rc)
+        {
+            kHlpFree(pRdrFile->pvMapping);
+            pRdrFile->pvMapping = NULL;
+            return rc;
+        }
+        pRdrFile->cMappings = 0;
+    }
+
+    *ppvBits = pRdrFile->pvMapping;
+    pRdrFile->cMappings++;
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnRead */
+static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+
+    /*
+     * Do a seek if needed.
+     */
+    if (pRdrFile->off != off)
+    {
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+        pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_SET, off);
+        if (pRdrFile->off < 0)
+        {
+            int rc = (int)-pRdrFile->off;
+            pRdrFile->off = -1;
+            return -rc;
+        }
+
+#elif K_OS == K_OS_OS2
+        ULONG ulNew;
+        APIRET rc;
+
+        rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew);
+        if (rc)
+        {
+            pRdrFile->off = -1;
+            return rc;
+        }
+
+#elif K_OS == K_OS_WINDOWS
+        LONG offHigh;
+        LONG offLow;
+
+        offHigh = (LONG)(off >> 32);
+        offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN);
+        if (    offLow != (LONG)off
+            ||  offHigh != (LONG)(off >> 32))
+        {
+            int rc = GetLastError();
+            if (!rc)
+                rc = KERR_GENERAL_FAILURE;
+            pRdrFile->off = -1;
+            return rc;
+        }
+
+#else
+# error "port me."
+#endif
+    }
+
+    /*
+     * Do the read.
+     */
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    {
+    KSSIZE cbRead;
+
+    cbRead = kHlpSys_read(pRdrFile->File, pvBuf, cb);
+    if (cbRead != cb)
+    {
+        pRdrFile->off = -1;
+        if (cbRead < 0)
+            return -cbRead;
+        return KERR_GENERAL_FAILURE;
+    }
+    }
+
+#elif K_OS == K_OS_OS2
+    {
+    ULONG cbRead = 0;
+    APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead);
+    if (rc)
+    {
+        pRdrFile->off = -1;
+        return rc;
+    }
+    if (cbRead != cb)
+    {
+        pRdrFile->off = -1;
+        return KERR_GENERAL_FAILURE;
+    }
+    }
+
+#elif K_OS == K_OS_WINDOWS
+    {
+    DWORD cbRead = 0;
+    if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL))
+    {
+        int rc = GetLastError();
+        if (!rc)
+            rc = KERR_GENERAL_FAILURE;
+        pRdrFile->off = -1;
+        return rc;
+    }
+    if (cbRead != cb)
+    {
+        pRdrFile->off = -1;
+        return KERR_GENERAL_FAILURE;
+    }
+    }
+
+#else
+# error "port me."
+#endif
+
+    pRdrFile->off = off + cb;
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnDestroy */
+static int krdrFileDestroy(PKRDR pRdr)
+{
+    PKRDRFILE    pRdrFile = (PKRDRFILE)pRdr;
+    int          rc;
+
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    rc = kHlpSys_close(pRdrFile->File);
+
+#elif K_OS == K_OS_OS2
+    rc = DosClose(pRdrFile->File);
+
+#elif K_OS == K_OS_WINDOWS
+    rc = 0;
+    if (!CloseHandle(pRdrFile->File))
+        rc = GetLastError();
+
+#else
+# error "port me"
+#endif
+
+    if (pRdrFile->pvMapping)
+    {
+        kHlpFree(pRdrFile->pvMapping);
+        pRdrFile->pvMapping = NULL;
+    }
+
+    kHlpFree(pRdr);
+    return rc;
+}
+
+
+/** @copydoc KRDROPS::pfnCreate */
+static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename)
+{
+    KSIZE       cchFilename;
+    PKRDRFILE   pRdrFile;
+
+    /*
+     * Open the file, determin its size and correct filename.
+     */
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+    int         File;
+    KFOFF       cb;
+    KFOFF       rc;
+    char        szFilename[1024];
+
+    cchFilename = kHlpStrLen(pszFilename);
+    if (cchFilename >= sizeof(szFilename))
+        return KERR_OUT_OF_RANGE;
+    kHlpMemCopy(szFilename, pszFilename, cchFilename + 1);
+    /** @todo normalize the filename. */
+
+# ifdef O_BINARY
+    File = kHlpSys_open(pszFilename, O_RDONLY | O_BINARY, 0);
+# else
+    File = kHlpSys_open(pszFilename, O_RDONLY, 0);
+# endif
+    if (File < 0)
+        return -File;
+
+    cb = kHlpSys_lseek(File, SEEK_END, 0);
+    rc = kHlpSys_lseek(File, SEEK_SET, 0);
+    if (    cb < 0
+        ||  rc < 0)
+    {
+        kHlpSys_close(File);
+        return cb < 0 ? -cb : -rc;
+    }
+
+#elif K_OS == K_OS_OS2
+    ULONG       ulAction = 0;
+    FILESTATUS3 Info;
+    APIRET      rc;
+    HFILE       File = 0;
+    KFOFF       cb;
+    char        szFilename[CCHMAXPATH];
+
+    if ((uintptr_t)pszFilename >= 0x20000000)
+    {
+        char *psz;
+        cchFilename = kHlpStrLen(szFilename);
+        psz = (char *)kHlpAllocA(cchFilename + 1);
+        kHlpMemCopy(psz, pszFilename, cchFilename + 1);
+        pszFilename = psz;
+    }
+    rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL,
+                 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
+                 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL,
+                 NULL);
+    if (rc)
+        return rc;
+
+    rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
+    if (rc)
+    {
+        DosClose(File);
+        return rc;
+    }
+
+    rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info));
+    if (rc)
+    {
+        DosClose(File);
+        return rc;
+    }
+    cb = Info.cbFile;
+
+#elif K_OS == K_OS_WINDOWS
+    SECURITY_ATTRIBUTES SecAttr;
+    DWORD               High;
+    DWORD               Low;
+    int                 rc;
+    HANDLE              File;
+    KFOFF            cb;
+    char                szFilename[MAX_PATH];
+
+    SecAttr.bInheritHandle = FALSE;
+    SecAttr.lpSecurityDescriptor = NULL;
+    SecAttr.nLength = 0;
+    File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL);
+    if (File == INVALID_HANDLE_VALUE)
+        return GetLastError();
+
+    if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL))
+    {
+        rc = GetLastError();
+        CloseHandle(File);
+        return rc;
+    }
+
+    SetLastError(0);
+    Low = GetFileSize(File, &High);
+    rc = GetLastError();
+    if (rc)
+    {
+        CloseHandle(File);
+        return rc;
+    }
+    cb = ((KFOFF)High << 32) | Low;
+
+#else
+# error "port me"
+#endif
+
+
+    /*
+     * Allocate the reader instance.
+     */
+    cchFilename = kHlpStrLen(szFilename);
+    pRdrFile = (PKRDRFILE)kHlpAlloc(sizeof(*pRdrFile) + cchFilename);
+    if (!pRdrFile)
+    {
+#if K_OS == K_OS_DARWIN \
+ || K_OS == K_OS_FREEBSD \
+ || K_OS == K_OS_LINUX \
+ || K_OS == K_OS_NETBSD \
+ || K_OS == K_OS_OPENBSD \
+ || K_OS == K_OS_SOLARIS
+        kHlpSys_close(File);
+#elif K_OS == K_OS_OS2
+        DosClose(File);
+#elif K_OS == K_OS_WINDOWS
+        CloseHandle(File);
+#else
+# error "port me"
+#endif
+        return KERR_NO_MEMORY;
+    }
+
+    /*
+     * Initialize it and return successfully.
+     */
+    pRdrFile->Core.u32Magic = KRDR_MAGIC;
+    pRdrFile->Core.pOps = &g_kRdrFileOps;
+    pRdrFile->File = File;
+    pRdrFile->cb = cb;
+    pRdrFile->off = 0;
+    pRdrFile->cMappings = 0;
+    pRdrFile->cPreps = 0;
+    kHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
+
+    *ppRdr = &pRdrFile->Core;
+    return 0;
+}
+
Index: /trunk/kRdr/kRdrInternal.h
===================================================================
--- /trunk/kRdr/kRdrInternal.h	(revision 2)
+++ /trunk/kRdr/kRdrInternal.h	(revision 2)
@@ -0,0 +1,124 @@
+/* $Id$ */
+/** @file
+ * kRdr - Internal Header.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * In addition to the permissions in the GNU Lesser General Public
+ * License, you are granted unlimited permission to link the compiled
+ * version of this file into combinations with other programs, and to
+ * distribute those combinations without any restriction coming from
+ * the use of this file.
+ *
+ * kStuff 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef ___kRdrInternal_h___
+#define ___kRdrInternal_h___
+
+#include <k/kHlpAssert.h>
+#include <k/kMagics.h>
+#include <k/kRdrAll.h>
+#include <k/kErrors.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup grp_kRdrInternal - Internals
+ * @internal
+ * @addtogroup grp_kRdr
+ * @{
+ */
+
+/** @def KRDR_STRICT
+ * If defined the kRdr assertions and other runtime checks will be enabled. */
+#ifdef K_ALL_STRICT
+# undef KRDR_STRICT
+# define KRDR_STRICT
+#endif
+
+/** @name Our Assert macros
+ * @{ */
+#ifdef KRDR_STRICT
+# define kRdrAssert(expr)                       kHlpAssert(expr)
+# define kRdrAssertReturn(expr, rcRet)          kHlpAssertReturn(expr, rcRet)
+# define kRdrAssertMsg(expr, msg)               kHlpAssertMsg(expr, msg)
+# define kRdrAssertMsgReturn(expr, msg, rcRet)  kHlpAssertMsgReturn(expr, msg, rcRet)
+#else   /* !KRDR_STRICT */
+# define kRdrAssert(expr)                       do { } while (0)
+# define kRdrAssertReturn(expr, rcRet)          do { if (!(expr)) return (rcRet); } while (0)
+# define kRdrAssertMsg(expr, msg)               do { } while (0)
+# define kRdrAssertMsgReturn(expr, msg, rcRet)  do { if (!(expr)) return (rcRet); } while (0)
+#endif  /* !KRDR_STRICT */
+
+#define kRdrAssertPtr(ptr)                      kRdrAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kRdrAssertPtrReturn(ptr, rcRet)         kRdrAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kRdrAssertPtrNull(ptr)                  kRdrAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kRdrAssertPtrNullReturn(ptr, rcRet)     kRdrAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kRdrAssertRC(rc)                        kRdrAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc)))
+#define kRdrAssertRCReturn(rc, rcRet)           kRdrAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet))
+#define kRdrAssertFailed()                      kRdrAssert(0)
+#define kRdrAssertFailedReturn(rcRet)           kRdrAssertReturn(0, (rcRet))
+#define kRdrAssertMsgFailed(msg)                kRdrAssertMsg(0, msg)
+#define kRdrAssertMsgFailedReturn(msg, rcRet)   kRdrAssertMsgReturn(0, msg, (rcRet))
+/** @} */
+
+/** Return / crash validation of a reader argument. */
+#define KRDR_VALIDATE_EX(pRdr, rc) \
+    do  { \
+        if (    (pRdr)->u32Magic != KRDR_MAGIC \
+            ||  (pRdr)->pOps == NULL \
+           )\
+        { \
+            return (rc); \
+        } \
+    } while (0)
+
+/** Return / crash validation of a reader argument. */
+#define KRDR_VALIDATE(pRdr) \
+    KRDR_VALIDATE_EX(pRdr, KERR_INVALID_PARAMETER)
+
+/** Return / crash validation of a reader argument. */
+#define KRDR_VALIDATE_VOID(pRdr) \
+    do  { \
+        if (    !K_VALID_PTR(pRdr) \
+            ||  (pRdr)->u32Magic != KRDR_MAGIC \
+            ||  (pRdr)->pOps == NULL \
+           )\
+        { \
+            return; \
+        } \
+    } while (0)
+
+
+/** @name Built-in Providers
+ * @{ */
+extern const KRDROPS g_kRdrFileOps;
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
