From a89043ab38c1a93bcce2951099c470e84e82a0c9 Mon Sep 17 00:00:00 2001
From: "sgk@google.com" <sgk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Sat, 25 Apr 2009 13:27:25 +0000
Subject: [PATCH] Capture Mozilla's codesighs, for use in executable sizing.

Vanilla code, no changes, except for the addition of:
* LICENSE, copied from elsewhere in the Mozilla tree;
* README.chromium, documenting what's going on.
* codesighs.gyp, for building with the rest of Chromium.
Review URL: http://codereview.chromium.org/93155

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14522 0039d316-1c4b-4281-b951-d872f2087c98
---
 build/all.gyp                               |    1 +
 third_party/codesighs/LICENSE               |  567 +++++
 third_party/codesighs/Makefile.in           |   75 +
 third_party/codesighs/README.chromium       |   13 +
 third_party/codesighs/autosummary.unix.bash |  250 +++
 third_party/codesighs/autosummary.win.bash  |  211 ++
 third_party/codesighs/basesummary.unix.bash |  254 +++
 third_party/codesighs/basesummary.win.bash  |  224 ++
 third_party/codesighs/codesighs.c           | 1075 +++++++++
 third_party/codesighs/codesighs.gyp         |   60 +
 third_party/codesighs/maptsvdifftool.c      | 1311 +++++++++++
 third_party/codesighs/msdump2symdb.c        | 1090 +++++++++
 third_party/codesighs/msmap.h               |  149 ++
 third_party/codesighs/msmap2tsv.c           | 2237 +++++++++++++++++++
 third_party/codesighs/nm2tsv.c              |  505 +++++
 third_party/codesighs/nm_wrap_osx.pl        |  105 +
 third_party/codesighs/readelf_wrap.pl       |  192 ++
 17 files changed, 8319 insertions(+)
 create mode 100644 third_party/codesighs/LICENSE
 create mode 100644 third_party/codesighs/Makefile.in
 create mode 100644 third_party/codesighs/README.chromium
 create mode 100755 third_party/codesighs/autosummary.unix.bash
 create mode 100755 third_party/codesighs/autosummary.win.bash
 create mode 100755 third_party/codesighs/basesummary.unix.bash
 create mode 100755 third_party/codesighs/basesummary.win.bash
 create mode 100644 third_party/codesighs/codesighs.c
 create mode 100644 third_party/codesighs/codesighs.gyp
 create mode 100644 third_party/codesighs/maptsvdifftool.c
 create mode 100644 third_party/codesighs/msdump2symdb.c
 create mode 100644 third_party/codesighs/msmap.h
 create mode 100644 third_party/codesighs/msmap2tsv.c
 create mode 100644 third_party/codesighs/nm2tsv.c
 create mode 100755 third_party/codesighs/nm_wrap_osx.pl
 create mode 100755 third_party/codesighs/readelf_wrap.pl

diff --git a/build/all.gyp b/build/all.gyp
index cb3e454bb5135..05524b9386238 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -28,6 +28,7 @@
         '../skia/skia.gyp:*',
         '../testing/gtest.gyp:*',
         '../third_party/bzip2/bzip2.gyp:*',
+        '../third_party/codesighs/codesighs.gyp:*',
         '../third_party/ffmpeg/ffmpeg.gyp:*',
         '../third_party/icu38/icu38.gyp:*',
         '../third_party/libjpeg/libjpeg.gyp:*',
diff --git a/third_party/codesighs/LICENSE b/third_party/codesighs/LICENSE
new file mode 100644
index 0000000000000..bc8f037c06d64
--- /dev/null
+++ b/third_party/codesighs/LICENSE
@@ -0,0 +1,567 @@
+                          MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation, method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your") means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a) under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code; or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a) under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d) Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2) separate from the Contributor Version;
+          3) for infringements caused by: i) third party modifications of
+          Contributor Version or ii) the combination of Modifications made
+          by that Contributor with other software (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+          (c) Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code. If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice. If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A. You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code. You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+     8.1. This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2. If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant") alleging that:
+
+     (a) such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant. If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b) any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3. If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4. In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed". "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+     ``The contents of this file are subject to the Mozilla Public License
+     Version 1.1 (the "License"); you may not use this file except in
+     compliance with the License. You may obtain a copy of the License at
+     http://www.mozilla.org/MPL/
+
+     Software distributed under the License is distributed on an "AS IS"
+     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+     License for the specific language governing rights and limitations
+     under the License.
+
+     The Original Code is ______________________________________.
+
+     The Initial Developer of the Original Code is ________________________.
+     Portions created by ______________________ are Copyright (C) ______
+     _______________________. All Rights Reserved.
+
+     Contributor(s): ______________________________________.
+
+     Alternatively, the contents of this file may be used under the terms
+     of the _____ license (the "[___] License"), in which case the
+     provisions of [______] License are applicable instead of those
+     above. If you wish to allow use of your version of this file only
+     under the terms of the [____] License and not to allow others to use
+     your version of this file under the MPL, indicate your decision by
+     deleting the provisions above and replace them with the notice and
+     other provisions required by the [___] License. If you do not delete
+     the provisions above, a recipient may use your version of this file
+     under either the MPL or the [___] License."
+
+     [NOTE: The text of this Exhibit A may differ slightly from the text of
+     the notices in the Source Code files of the Original Code. You should
+     use the text of this Exhibit A rather than the text found in the
+     Original Code Source Code for Your Modifications.]
+
+     ----------------------------------------------------------------------
+
+     AMENDMENTS
+
+     The Netscape Public License Version 1.1 ("NPL") consists of the
+     Mozilla Public License Version 1.1 with the following Amendments,
+     including Exhibit A-Netscape Public License. Files identified with
+     "Exhibit A-Netscape Public License" are governed by the Netscape
+     Public License Version 1.1.
+
+     Additional Terms applicable to the Netscape Public License.
+          I. Effect.
+          These additional terms described in this Netscape Public
+          License -- Amendments shall apply to the Mozilla Communicator
+          client code and to all Covered Code under this License.
+
+          II. "Netscape's Branded Code" means Covered Code that Netscape
+          distributes and/or permits others to distribute under one or more
+          trademark(s) which are controlled by Netscape but which are not
+          licensed for use under this License.
+
+          III. Netscape and logo.
+          This License does not grant any rights to use the trademarks
+          "Netscape", the "Netscape N and horizon" logo or the "Netscape
+          lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript",
+          "Smart Browsing" even if such marks are included in the Original
+          Code or Modifications.
+
+          IV. Inability to Comply Due to Contractual Obligation.
+          Prior to licensing the Original Code under this License, Netscape
+          has licensed third party code for use in Netscape's Branded Code.
+          To the extent that Netscape is limited contractually from making
+          such third party code available under this License, Netscape may
+          choose to reintegrate such code into Covered Code without being
+          required to distribute such code in Source Code form, even if
+          such code would otherwise be considered "Modifications" under
+          this License.
+
+          V. Use of Modifications and Covered Code by Initial Developer.
+               V.1. In General.
+               The obligations of Section 3 apply to Netscape, except to
+               the extent specified in this Amendment, Section V.2 and V.3.
+
+               V.2. Other Products.
+               Netscape may include Covered Code in products other than the
+               Netscape's Branded Code which are released by Netscape
+               during the two (2) years following the release date of the
+               Original Code, without such additional products becoming
+               subject to the terms of this License, and may license such
+               additional products on different terms from those contained
+               in this License.
+
+               V.3. Alternative Licensing.
+               Netscape may license the Source Code of Netscape's Branded
+               Code, including Modifications incorporated therein, without
+               such Netscape Branded Code becoming subject to the terms of
+               this License, and may license such Netscape Branded Code on
+               different terms from those contained in this License.
+
+          VI. Litigation.
+          Notwithstanding the limitations of Section 11 above, the
+          provisions regarding litigation in Section 11(a), (b) and (c) of
+          the License shall apply to all disputes relating to this License.
+
+     EXHIBIT A-Netscape Public License.
+
+          "The contents of this file are subject to the Netscape Public
+          License Version 1.1 (the "License"); you may not use this file
+          except in compliance with the License. You may obtain a copy of
+          the License at http://www.mozilla.org/NPL/
+
+          Software distributed under the License is distributed on an "AS
+          IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+          implied. See the License for the specific language governing
+          rights and limitations under the License.
+
+          The Original Code is Mozilla Communicator client code, released
+          March 31, 1998.
+
+          The Initial Developer of the Original Code is Netscape
+          Communications Corporation. Portions created by Netscape are
+          Copyright (C) 1998-1999 Netscape Communications Corporation. All
+          Rights Reserved.
+
+          Contributor(s): ______________________________________.
+
+          Alternatively, the contents of this file may be used under the
+          terms of the _____ license (the "[___] License"), in which case
+          the provisions of [______] License are applicable  instead of
+          those above. If you wish to allow use of your version of this
+          file only under the terms of the [____] License and not to allow
+          others to use your version of this file under the NPL, indicate
+          your decision by deleting the provisions above and replace  them
+          with the notice and other provisions required by the [___]
+          License. If you do not delete the provisions above, a recipient
+          may use your version of this file under either the NPL or the
+          [___] License."
diff --git a/third_party/codesighs/Makefile.in b/third_party/codesighs/Makefile.in
new file mode 100644
index 0000000000000..e243f2d325bbf
--- /dev/null
+++ b/third_party/codesighs/Makefile.in
@@ -0,0 +1,75 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Garrett Arch Blythe
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+REQUIRES = $(NULL)
+
+CSRCS += \
+		codesighs.c \
+		maptsvdifftool.c \
+		$(NULL)
+
+ifeq ($(OS_ARCH),WINNT)
+CSRCS += \
+		msmap2tsv.c \
+		msdump2symdb.c \
+		$(NULL)
+else
+CSRCS += \
+		nm2tsv.c \
+		$(NULL)
+endif
+
+SIMPLE_PROGRAMS	= $(CSRCS:.c=$(BIN_SUFFIX))
+
+include $(topsrcdir)/config/config.mk
+
+ifeq ($(OS_ARCH),WINNT)
+OS_LIBS += \
+		imagehlp.lib \
+		$(NULL)
+endif
+
+
+include $(topsrcdir)/config/rules.mk
diff --git a/third_party/codesighs/README.chromium b/third_party/codesighs/README.chromium
new file mode 100644
index 0000000000000..36d4079c62ab3
--- /dev/null
+++ b/third_party/codesighs/README.chromium
@@ -0,0 +1,13 @@
+This is Chromium's copy of the Mozilla codesighs tool.
+
+Originally obtained from Mozilla's Mercurial repository
+on 17 April 2009:
+
+http://hg.mozilla.org/mozilla-central/tools/codesighs
+
+The LICENSE from http://hg.mozilla.org/mozilla-central has been copied
+here.
+
+There are no local changes to the code itself.
+
+A codesighs.gyp file has been added for building with Chromium.
diff --git a/third_party/codesighs/autosummary.unix.bash b/third_party/codesighs/autosummary.unix.bash
new file mode 100755
index 0000000000000..a35f92a89068e
--- /dev/null
+++ b/third_party/codesighs/autosummary.unix.bash
@@ -0,0 +1,250 @@
+#!/bin/bash
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is autosummary.linx.bash code, released
+# Oct 10, 2002.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Garrett Arch Blythe, 10-October-2002
+#   Simon Fraser <sfraser@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+#
+# Check for optional objdir
+# 
+if [ "$1" = "-o" ]; then 
+OBJROOT="$2"
+shift
+shift
+else
+OBJROOT="./mozilla"
+fi
+
+if [ "$1" = "-s" ]; then 
+SRCROOT="$2"
+shift
+shift
+else
+SRCROOT="./mozilla"
+fi
+
+#
+#   A little help for my friends.
+#
+if [ "-h" == "$1" ];then 
+    SHOWHELP="1"
+fi
+if [ "--help" == "$1" ];then 
+    SHOWHELP="1"
+fi
+if [ "" == "$1" ]; then
+    SHOWHELP="1"
+fi
+if [ "" == "$2" ]; then
+    SHOWHELP="1"
+fi
+if [ "" == "$3" ]; then
+    SHOWHELP="1"
+fi
+
+
+#
+#   Show the help if required.
+#
+if [ $SHOWHELP ]; then
+    echo "usage: $0 <save_results> <old_results> <summary>"
+    echo "  <save_results> is a file that will receive the results of this run."
+    echo "    This file can be used in a future run as the old results."
+    echo "  <old_results> is a results file from a previous run."
+    echo "    It is used to diff with current results and come up with a summary"
+    echo "      of changes."
+    echo "    It is OK if the file does not exist, just supply the argument."
+    echo "  <summary> is a file which will contain a human readable report."
+    echo "    This file is most useful by providing more information than the"
+    echo "      normally single digit output of this script."
+    echo ""
+    echo "Run this command from the parent directory of the mozilla tree."
+    echo ""
+    echo "This command will output two numbers to stdout that will represent"
+    echo "  the total size of all code and data, and a delta from the prior."
+    echo "  the old results."
+    echo "For much more detail on size drifts refer to the summary report."
+    echo ""
+    echo "This tool reports on all executables in the directory tree."
+    exit
+fi
+
+#
+#   Stash our arguments away.
+#
+COPYSORTTSV="$1"
+OLDTSVFILE="$2"
+SUMMARYFILE="$3"
+
+OSTYPE=`uname -s`
+
+#
+#   On Mac OS X, use the --zerodrift option to maptsvdifftool
+#
+if [ $OSTYPE == "Darwin" ]; then
+ZERODRIFT="--zerodrift"
+else
+ZERODRIFT=""
+fi
+
+#
+#   Create our temporary directory.
+#   mktemp on Darwin doesn't support -d (suckage)
+#
+if [ $OSTYPE == "Darwin" ]; then
+ZERODRIFT="--zerodrift"
+MYTMPDIR=`mktemp ./codesighs.tmp.XXXXXXXX`
+rm $MYTMPDIR
+mkdir $MYTMPDIR
+else
+MYTMPDIR=`mktemp -d ./codesighs.tmp.XXXXXXXX`
+fi
+
+#
+#   Find all relevant files.
+#
+ALLFILES="$MYTMPDIR/allfiles.list"
+
+if [ $OSTYPE == "Darwin" ] || [ $OSTYPE == "SunOS" ]; then
+find $OBJROOT/dist/bin ! -type d > $ALLFILES
+else
+find $OBJROOT/dist/bin -not -type d > $ALLFILES
+fi
+
+# Check whether we have 'eu-readelf' or 'readelf' available.
+# If we do, it will give more accurate symbol sizes than nm.
+
+if [ $OSTYPE == "Darwin" ]; then
+  USE_READELF=
+else
+READELF_PROG=`which eu-readelf 2>/dev/null | grep /eu-readelf$`
+if test "$READELF_PROG"; then
+  USE_READELF=1
+else
+  READELF_PROG=`which readelf 2>/dev/null | grep /readelf$`
+  if test "$READELF_PROG"; then
+    # Check whether we need -W
+    if readelf --help | grep "\--wide" >&/dev/null; then
+      READELF_PROG="readelf -W"
+    else
+      READELF_PROG="readelf"
+    fi
+    USE_READELF=1
+  else
+    USE_READELF=
+  fi
+fi
+fi
+
+RAWTSVFILE="$MYTMPDIR/raw.tsv"
+if test "$USE_READELF"; then
+export READELF_PROG
+xargs -n 1 $SRCROOT/tools/codesighs/readelf_wrap.pl < $ALLFILES > $RAWTSVFILE 2> /dev/null
+else
+
+#
+#   Produce the cumulative nm output.
+#   We are very particular on what switches to use.
+#   nm --format=bsd --size-sort --print-file-name --demangle
+#
+#   Darwin (Mac OS X) has a lame nm that we have to wrap in a perl
+#   script to get decent output.
+#
+NMRESULTS="$MYTMPDIR/nm.txt"
+if [ $OSTYPE == "Darwin" ]; then
+xargs -n 1 $SRCROOT/tools/codesighs/nm_wrap_osx.pl < $ALLFILES  > $NMRESULTS 2> /dev/null
+else
+xargs -n 1 nm --format=bsd --size-sort --print-file-name --demangle < $ALLFILES > $NMRESULTS 2> /dev/null
+fi
+
+
+#
+#   Produce the TSV output.
+#
+
+$OBJROOT/dist/bin/nm2tsv --input $NMRESULTS > $RAWTSVFILE
+
+fi  # USE_READELF
+
+#
+#   Sort the TSV output for useful diffing and eyeballing in general.
+#
+sort -r $RAWTSVFILE > $COPYSORTTSV
+
+
+#
+#   If a historical file was specified, diff it with our sorted tsv values.
+#   Run it through a tool to summaries the diffs to the module
+#       level report.
+#   Otherwise, generate the module level report from our new data.
+#
+
+rm -f $SUMMARYFILE
+DIFFFILE="$MYTMPDIR/diff.txt"
+if [ -e $OLDTSVFILE ]; then
+  diff $OLDTSVFILE $COPYSORTTSV > $DIFFFILE
+  $OBJROOT/dist/bin/maptsvdifftool $ZERODRIFT --input $DIFFFILE >> $SUMMARYFILE
+else
+  $OBJROOT/dist/bin/codesighs --modules --input $COPYSORTTSV >> $SUMMARYFILE
+fi
+
+
+#
+#   Output our numbers, that will let tinderbox specify everything all
+#       at once.
+#   First number is in fact the total size of all code and data in the map
+#       files parsed.
+#   Second number, if present, is growth/shrinkage.
+#
+
+if [ $TINDERBOX_OUTPUT ]; then
+    echo -n "__codesize:"
+fi
+$OBJROOT/dist/bin/codesighs --totalonly --input $COPYSORTTSV
+
+if [ -e $DIFFFILE ]; then
+if [ $TINDERBOX_OUTPUT ]; then
+    echo -n "__codesizeDiff:"
+fi
+    $OBJROOT/dist/bin/maptsvdifftool $ZERODRIFT --summary --input $DIFFFILE
+fi
+
+#
+#   Remove our temporary directory.
+#
+rm -rf $MYTMPDIR
diff --git a/third_party/codesighs/autosummary.win.bash b/third_party/codesighs/autosummary.win.bash
new file mode 100755
index 0000000000000..d501625b0aef3
--- /dev/null
+++ b/third_party/codesighs/autosummary.win.bash
@@ -0,0 +1,211 @@
+#!/bin/bash
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is autosummary.win.bash code, released
+# Oct 3, 2002.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Garrett Arch Blythe, 03-October-2002
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+#
+# Check for optional objdir
+# 
+if [ "$1" = "-o" ]; then 
+OBJROOT="$2"
+shift
+shift
+else
+OBJROOT="./mozilla"
+fi
+
+if [ "$1" = "-s" ]; then 
+SRCROOT="$2"
+shift
+shift
+else
+SRCROOT="./mozilla"
+fi
+
+#
+#   A little help for my friends.
+#
+if [ "-h" == "$1" ];then 
+    SHOWHELP="1"
+fi
+if [ "--help" == "$1" ];then 
+    SHOWHELP="1"
+fi
+if [ "" == "$1" ]; then
+    SHOWHELP="1"
+fi
+if [ "" == "$2" ]; then
+    SHOWHELP="1"
+fi
+if [ "" == "$3" ]; then
+    SHOWHELP="1"
+fi
+
+
+#
+#   Show the help if required.
+#
+if [ $SHOWHELP ]; then
+    echo "usage: $0 <save_results> <old_results> <summary>"
+    echo "  <save_results> is a file that will receive the results of this run."
+    echo "    This file can be used in a future run as the old results."
+    echo "  <old_results> is a results file from a previous run."
+    echo "    It is used to diff with current results and come up with a summary"
+    echo "      of changes."
+    echo "    It is OK if the file does not exist, just supply the argument."
+    echo "  <summary> is a file which will contain a human readable report."
+    echo "    This file is most useful by providing more information than the"
+    echo "      normally single digit output of this script."
+    echo ""
+    echo "Run this command from the parent directory of the mozilla tree."
+    echo ""
+    echo "This command will output two numbers to stdout that will represent"
+    echo "  the total size of all code and data, and a delta from the prior."
+    echo "  the old results."
+    echo "For much more detail on size drifts refer to the summary report."
+    echo ""
+    echo "This tool reports on all executables in the directory tree."
+    exit
+fi
+
+
+#
+#   Stash our arguments away.
+#
+COPYSORTTSV="$1"
+OLDTSVFILE="$2"
+SUMMARYFILE="$3"
+
+
+#
+#   Create our temporary directory.
+#
+MYTMPDIR=`mktemp -d ./codesighs.tmp.XXXXXXXX`
+
+
+#
+#   Find the types of files we are interested in.
+#
+ONEFINDPASS="$MYTMPDIR/onefind.list"
+/usr/bin/find $OBJROOT -type f -name "*.obj" -or -name "*.map" | while read FNAME; do
+    cygpath -m $FNAME >> $ONEFINDPASS
+done
+
+
+#
+#   Find all object files.
+#
+ALLOBJSFILE="$MYTMPDIR/allobjs.list"
+grep -i "\.obj$" < $ONEFINDPASS > $ALLOBJSFILE
+
+
+#
+#   Get a dump of the symbols in every object file.
+#
+ALLOBJSYMSFILE="$MYTMPDIR/allobjsyms.list"
+xargs -n 1 dumpbin.exe /symbols < $ALLOBJSFILE > $ALLOBJSYMSFILE 2> /dev/null
+
+
+#
+#   Produce the symdb for the symbols in all object files.
+#
+SYMDBFILE="$MYTMPDIR/symdb.tsv"
+$OBJROOT/dist/bin/msdump2symdb --input $ALLOBJSYMSFILE | /usr/bin/sort > $SYMDBFILE 2> /dev/null
+
+
+#
+#   Find all map files.
+#
+ALLMAPSFILE="$MYTMPDIR/allmaps.list"
+grep -i "\.map$" < $ONEFINDPASS > $ALLMAPSFILE
+
+
+#
+#   Produce the TSV output.
+#
+RAWTSVFILE="$MYTMPDIR/raw.tsv"
+$OBJROOT/dist/bin/msmap2tsv --symdb $SYMDBFILE --batch < $ALLMAPSFILE > $RAWTSVFILE 2> /dev/null
+
+
+#
+#   Sort the TSV output for useful diffing and eyeballing in general.
+#
+/usr/bin/sort -r $RAWTSVFILE > $COPYSORTTSV
+
+
+#
+#   If a historical file was specified, diff it with our sorted tsv values.
+#   Run it through a tool to summaries the diffs to the module
+#       level report.
+#   Otherwise, generate the module level report from our new data.
+#
+rm -f $SUMMARYFILE
+DIFFFILE="$MYTMPDIR/diff.txt"
+if [ -e $OLDTSVFILE ]; then
+  diff $OLDTSVFILE $COPYSORTTSV > $DIFFFILE
+  $OBJROOT/dist/bin/maptsvdifftool --negation --input $DIFFFILE | dos2unix >> $SUMMARYFILE
+else
+  $OBJROOT/dist/bin/codesighs --modules --input $COPYSORTTSV | dos2unix >> $SUMMARYFILE
+fi
+
+
+#
+#   Output our numbers, that will let tinderbox specify everything all
+#       at once.
+#   First number is in fact the total size of all code and data in the map
+#       files parsed.
+#   Second number, if present, is growth/shrinkage.
+#
+
+if [ $TINDERBOX_OUTPUT ]; then
+    echo -n "__codesize:"
+fi
+$OBJROOT/dist/bin/codesighs --totalonly --input $COPYSORTTSV | dos2unix
+
+
+if [ -e $DIFFFILE ]; then
+if [ $TINDERBOX_OUTPUT ]; then
+    echo -n "__codesizeDiff:"
+fi
+    $OBJROOT/dist/bin/maptsvdifftool --negation --summary --input $DIFFFILE | dos2unix
+fi
+
+#
+#   Remove our temporary directory.
+#
+rm -rf $MYTMPDIR
diff --git a/third_party/codesighs/basesummary.unix.bash b/third_party/codesighs/basesummary.unix.bash
new file mode 100755
index 0000000000000..34cd298c7e3b1
--- /dev/null
+++ b/third_party/codesighs/basesummary.unix.bash
@@ -0,0 +1,254 @@
+#!/bin/bash
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is basesummary.linx.bash code, released
+# Nov 15, 2002.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Garrett Arch Blythe, 15-November-2002
+#   Simon Fraser <sfraser@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+#
+# Check for optional objdir
+# 
+if [ "$1" = "-o" ]; then 
+OBJROOT="$2"
+shift
+shift
+else
+OBJROOT="./mozilla"
+fi
+
+if [ "$1" = "-s" ]; then
+SRCROOT="$2"
+shift
+shift
+else
+SRCROOT="./mozilla"
+fi
+
+OSTYPE=`uname -s`
+
+if [ $OSTYPE == "Darwin" ]; then
+MANIFEST="$SRCROOT/embedding/config/basebrowser-mac-macho"
+else
+MANIFEST="$SRCROOT/embedding/config/basebrowser-unix"
+fi
+
+#
+#   A little help for my friends.
+#
+if [ "-h" == "$1" ];then 
+    SHOWHELP="1"
+fi
+if [ "--help" == "$1" ];then 
+    SHOWHELP="1"
+fi
+if [ "" == "$1" ]; then
+    SHOWHELP="1"
+fi
+if [ "" == "$2" ]; then
+    SHOWHELP="1"
+fi
+if [ "" == "$3" ]; then
+    SHOWHELP="1"
+fi
+
+
+#
+#   Show the help if required.
+#
+if [ $SHOWHELP ]; then
+    echo "usage: $0 <save_results> <old_results> <summary>"
+    echo "  <save_results> is a file that will receive the results of this run."
+    echo "    This file can be used in a future run as the old results."
+    echo "  <old_results> is a results file from a previous run."
+    echo "    It is used to diff with current results and come up with a summary"
+    echo "      of changes."
+    echo "    It is OK if the file does not exist, just supply the argument."
+    echo "  <summary> is a file which will contain a human readable report."
+    echo "    This file is most useful by providing more information than the"
+    echo "      normally single digit output of this script."
+    echo ""
+    echo "Run this command from the parent directory of the mozilla tree."
+    echo ""
+    echo "This command will output two numbers to stdout that will represent"
+    echo "  the total size of all code and data, and a delta from the prior."
+    echo "  the old results."
+    echo "For much more detail on size drifts refer to the summary report."
+    echo ""
+    echo "This tool reports on executables listed in the following file:"
+    echo "$MANIFEST"
+    exit
+fi
+
+
+#
+#   Stash our arguments away.
+#
+COPYSORTTSV="$1"
+OLDTSVFILE="$2"
+SUMMARYFILE="$3"
+
+
+#
+#   On Mac OS X, use the --zerodrift option to maptsvdifftool
+#
+if [ $OSTYPE == "Darwin" ]; then
+ZERODRIFT="--zerodrift"
+else
+ZERODRIFT=""
+fi
+
+
+#
+#   Create our temporary directory.
+#   mktemp on Darwin doesn't support -d (suckage)
+#
+if [ $OSTYPE == "Darwin" ]; then
+MYTMPDIR=`mktemp ./codesighs.tmp.XXXXXXXX`
+rm $MYTMPDIR
+mkdir $MYTMPDIR
+else
+MYTMPDIR=`mktemp -d ./codesighs.tmp.XXXXXXXX`
+fi
+
+
+# Check whether we have 'eu-readelf' or 'readelf' available.
+# If we do, it will give more accurate symbol sizes than nm.
+
+if [ $OSTYPE == "Darwin" ]; then
+  USE_READELF=
+else
+READELF_PROG=`which eu-readelf 2>/dev/null | grep /eu-readelf$`
+if test "$READELF_PROG"; then
+  USE_READELF=1
+else
+  READELF_PROG=`which readelf 2>/dev/null | grep /readelf$`
+  if test "$READELF_PROG"; then
+    # Check whether we need -W
+    if readelf --help | grep "\--wide" >&/dev/null; then
+      READELF_PROG="readelf -W"
+    else
+      READELF_PROG="readelf"
+    fi
+    USE_READELF=1
+  else
+    USE_READELF=
+  fi
+fi
+fi
+
+#
+#   Find all relevant files.
+#
+ALLFILES="$MYTMPDIR/allfiles.list"
+grep -v '[\;\[]' < $MANIFEST | grep -v '^$' | sed "s|^|${OBJROOT}/dist/bin/|" > $ALLFILES
+
+
+RAWTSVFILE="$MYTMPDIR/raw.tsv"
+
+if test "$USE_READELF"; then
+export READELF_PROG
+xargs -n 1 $SRCROOT/tools/codesighs/readelf_wrap.pl < $ALLFILES > $RAWTSVFILE
+else
+
+#
+#   Produce the cumulative nm output.
+#   We are very particular on what switches to use.
+#   nm --format=bsd --size-sort --print-file-name --demangle
+#
+#   Darwin (Mac OS X) has a lame nm that we have to wrap in a perl
+#   script to get decent output.
+#
+NMRESULTS="$MYTMPDIR/nm.txt"
+if [ $OSTYPE == "Darwin" ]; then
+xargs -n 1 $SRCROOT/tools/codesighs/nm_wrap_osx.pl < $ALLFILES  > $NMRESULTS 2> /dev/null
+else
+xargs -n 1 nm --format=bsd --size-sort --print-file-name --demangle < $ALLFILES > $NMRESULTS 2> /dev/null
+fi
+
+#
+#   Produce the TSV output.
+#
+$OBJROOT/dist/bin/nm2tsv --input $NMRESULTS > $RAWTSVFILE
+
+fi  # USE_READELF
+
+#
+#   Sort the TSV output for useful diffing and eyeballing in general.
+#
+sort -r $RAWTSVFILE > $COPYSORTTSV
+
+
+#
+#   If a historical file was specified, diff it with our sorted tsv values.
+#   Run it through a tool to summaries the diffs to the module
+#       level report.
+#   Otherwise, generate the module level report from our new data.
+#
+rm -f $SUMMARYFILE
+DIFFFILE="$MYTMPDIR/diff.txt"
+if [ -e $OLDTSVFILE ]; then
+  diff $OLDTSVFILE $COPYSORTTSV > $DIFFFILE
+  $OBJROOT/dist/bin/maptsvdifftool $ZERODRIFT --input $DIFFFILE >> $SUMMARYFILE
+else
+  $OBJROOT/dist/bin/codesighs --modules --input $COPYSORTTSV >> $SUMMARYFILE
+fi
+
+
+#
+#   Output our numbers, that will let tinderbox specify everything all
+#       at once.
+#   First number is in fact the total size of all code and data in the map
+#       files parsed.
+#   Second number, if present, is growth/shrinkage.
+#
+
+if [ $TINDERBOX_OUTPUT ]; then
+    echo -n "__codesize:"
+fi
+$OBJROOT/dist/bin/codesighs --totalonly --input $COPYSORTTSV
+
+if [ -e $DIFFFILE ]; then
+if [ $TINDERBOX_OUTPUT ]; then
+    echo -n "__codesizeDiff:"
+fi
+    $OBJROOT/dist/bin/maptsvdifftool $ZERODRIFT --summary --input $DIFFFILE
+fi
+
+#
+#   Remove our temporary directory.
+#
+rm -rf $MYTMPDIR
diff --git a/third_party/codesighs/basesummary.win.bash b/third_party/codesighs/basesummary.win.bash
new file mode 100755
index 0000000000000..1e05859060784
--- /dev/null
+++ b/third_party/codesighs/basesummary.win.bash
@@ -0,0 +1,224 @@
+#!/bin/bash
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is basesummary.win.bash code, released
+# Nov 15, 2002.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Garrett Arch Blythe, 15-November-2002
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+
+#
+# Check for optional objdir
+# 
+if [ "$1" = "-o" ]; then 
+OBJROOT="$2"
+shift
+shift
+else
+OBJROOT="./mozilla"
+fi
+
+if [ "$1" = "-s" ]; then 
+SRCROOT="$2"
+shift
+shift
+else
+SRCROOT="./mozilla"
+fi
+
+MANIFEST="$SRCROOT/embedding/config/basebrowser-win"
+
+#
+#   A little help for my friends.
+#
+if [ "-h" == "$1" ];then 
+    SHOWHELP="1"
+fi
+if [ "--help" == "$1" ];then 
+    SHOWHELP="1"
+fi
+if [ "" == "$1" ]; then
+    SHOWHELP="1"
+fi
+if [ "" == "$2" ]; then
+    SHOWHELP="1"
+fi
+if [ "" == "$3" ]; then
+    SHOWHELP="1"
+fi
+
+
+#
+#   Show the help if required.
+#
+if [ $SHOWHELP ]; then
+    echo "usage: $0 <save_results> <old_results> <summary>"
+    echo "  <save_results> is a file that will receive the results of this run."
+    echo "    This file can be used in a future run as the old results."
+    echo "  <old_results> is a results file from a previous run."
+    echo "    It is used to diff with current results and come up with a summary"
+    echo "      of changes."
+    echo "    It is OK if the file does not exist, just supply the argument."
+    echo "  <summary> is a file which will contain a human readable report."
+    echo "    This file is most useful by providing more information than the"
+    echo "      normally single digit output of this script."
+    echo ""
+    echo "Run this command from the parent directory of the mozilla tree."
+    echo ""
+    echo "This command will output two numbers to stdout that will represent"
+    echo "  the total size of all code and data, and a delta from the prior."
+    echo "  the old results."
+    echo "For much more detail on size drifts refer to the summary report."
+    echo ""
+    echo "This tool reports on executables listed in the following file:"
+    echo "$MANIFEST"
+    exit
+fi
+
+
+#
+#   Stash our arguments away.
+#
+COPYSORTTSV="$1"
+OLDTSVFILE="$2"
+SUMMARYFILE="$3"
+
+
+#
+#   Create our temporary directory.
+#
+MYTMPDIR=`mktemp -d ./codesighs.tmp.XXXXXXXX`
+
+
+#
+#   Find the types of files we are interested in.
+#
+ONEFINDPASS="$MYTMPDIR/onefind.list"
+/usr/bin/find $OBJROOT -type f -name "*.obj" -or -name "*.map" | while read FNAME; do
+    cygpath -m $FNAME >> $ONEFINDPASS
+done
+
+
+#
+#   Find all object files.
+#
+ALLOBJSFILE="$MYTMPDIR/allobjs.list"
+grep -i "\.obj$" < $ONEFINDPASS > $ALLOBJSFILE
+
+
+#
+#   Get a dump of the symbols in every object file.
+#
+ALLOBJSYMSFILE="$MYTMPDIR/allobjsyms.list"
+xargs -n 1 dumpbin.exe /symbols < $ALLOBJSFILE > $ALLOBJSYMSFILE 2> /dev/null
+
+
+#
+#   Produce the symdb for the symbols in all object files.
+#
+SYMDBFILE="$MYTMPDIR/symdb.tsv"
+$OBJROOT/dist/bin/msdump2symdb --input $ALLOBJSYMSFILE | /usr/bin/sort > $SYMDBFILE 2> /dev/null
+
+
+#
+#   Find all map files.
+#
+ALLMAPSFILE="$MYTMPDIR/allmaps.list"
+grep -i "\.map$" < $ONEFINDPASS > $ALLMAPSFILE
+
+
+#
+#   Figure out which modules in specific we care about.
+#   The relevant set meaning that the map file name prefix must be found
+#       in the file mozilla/embedding/config/basebrowser-win.
+#
+RELEVANTSETFILE="$MYTMPDIR/relevant.set"
+grep -v '\;' < $MANIFEST | sed 's/.*\\//' | grep '\.[eEdD][xXlL][eElL]' | sed 's/\.[eEdD][xXlL][eElL]//' > $RELEVANTSETFILE
+RELEVANTARG=`xargs -n 1 echo --match-module < $RELEVANTSETFILE`
+
+
+#
+#   Produce the TSV output.
+#
+RAWTSVFILE="$MYTMPDIR/raw.tsv"
+$OBJROOT/dist/bin/msmap2tsv --symdb $SYMDBFILE --batch $RELEVANTARG < $ALLMAPSFILE > $RAWTSVFILE 2> /dev/null
+
+
+#
+#   Sort the TSV output for useful diffing and eyeballing in general.
+#
+/usr/bin/sort -r $RAWTSVFILE > $COPYSORTTSV
+
+
+#
+#   If a historical file was specified, diff it with our sorted tsv values.
+#   Run it through a tool to summaries the diffs to the module
+#       level report.
+#   Otherwise, generate the module level report from our new data.
+#
+rm -f $SUMMARYFILE
+DIFFFILE="$MYTMPDIR/diff.txt"
+if [ -e $OLDTSVFILE ]; then
+  diff $OLDTSVFILE $COPYSORTTSV > $DIFFFILE
+  $OBJROOT/dist/bin/maptsvdifftool --negation --input $DIFFFILE | dos2unix >> $SUMMARYFILE
+else
+  $OBJROOT/dist/bin/codesighs --modules --input $COPYSORTTSV | dos2unix >> $SUMMARYFILE
+fi
+
+
+#
+#   Output our numbers, that will let tinderbox specify everything all
+#       at once.
+#   First number is in fact the total size of all code and data in the map
+#       files parsed.
+#   Second number, if present, is growth/shrinkage.
+#
+
+if [ $TINDERBOX_OUTPUT ]; then
+    echo -n "__codesize:"
+fi
+$OBJROOT/dist/bin/codesighs --totalonly --input $COPYSORTTSV | dos2unix
+
+if [ -e $DIFFFILE ]; then
+if [ $TINDERBOX_OUTPUT ]; then
+    echo -n "__codesizeDiff:"
+fi
+    $OBJROOT/dist/bin/maptsvdifftool --negation --summary --input $DIFFFILE | dos2unix
+fi
+
+#
+#   Remove our temporary directory.
+#
+rm -rf $MYTMPDIR
diff --git a/third_party/codesighs/codesighs.c b/third_party/codesighs/codesighs.c
new file mode 100644
index 0000000000000..f20fbb1e62ddb
--- /dev/null
+++ b/third_party/codesighs/codesighs.c
@@ -0,0 +1,1075 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is codesighs.c code, released
+ * Oct 3, 2002.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Garrett Arch Blythe, 03-October-2002
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+
+#define ERROR_REPORT(num, val, msg)   fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
+#define CLEANUP(ptr)    do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
+
+
+typedef struct __struct_Options
+/*
+**  Options to control how we perform.
+**
+**  mProgramName    Used in help text.
+**  mInput          File to read for input.
+**                  Default is stdin.
+**  mInputName      Name of the file.
+**  mOutput         Output file, append.
+**                  Default is stdout.
+**  mOutputName     Name of the file.
+**  mHelp           Whether or not help should be shown.
+**  mModules        Output module by module information.
+**  mTotalOnly      Only output one number, the total.
+**  mMinSize        Ignore lines below this size.
+**  mMaxSize        Ignore lines above this size.
+**  mMatchScopes    For a line to be processed, it should match.
+**  mMachClasses    For a line to be processed, it should match.
+**  mMatchModules   For a line to be processed, it should match.
+**  mMatchSections  For a line to be processed, it should match.
+**  mMatchObjects   For a line to be processed, it should match.
+**  mMatchSymbols   For a line to be processed, it should match.
+*/
+{
+    const char* mProgramName;
+    FILE* mInput;
+    char* mInputName;
+    FILE* mOutput;
+    char* mOutputName;
+    int mHelp;
+    int mModules;
+    int mTotalOnly;
+    unsigned long mMinSize;
+    unsigned long mMaxSize;
+    char** mMatchScopes;
+    unsigned mMatchScopeCount;
+    char** mMatchClasses;
+    unsigned mMatchClassCount;
+    char** mMatchModules;
+    unsigned mMatchModuleCount;
+    char** mMatchSections;
+    unsigned mMatchSectionCount;
+    char** mMatchObjects;
+    unsigned mMatchObjectCount;
+    char** mMatchSymbols;
+    unsigned mMatchSymbolCount;
+}
+Options;
+
+
+typedef struct __struct_Switch
+/*
+**  Command line options.
+*/
+{
+    const char* mLongName;
+    const char* mShortName;
+    int mHasValue;
+    const char* mValue;
+    const char* mDescription;
+}
+Switch;
+
+#define DESC_NEWLINE "\n\t\t"
+
+static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
+static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
+static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
+static Switch gModuleSwitch = {"--modules", "-m", 0, NULL, "Output individual module numbers as well."};
+static Switch gTotalSwitch = {"--totalonly", "-t", 0, NULL, "Output only one number." DESC_NEWLINE "The total overall size." DESC_NEWLINE "Overrides other output options."};
+static Switch gMinSize = {"--min-size", "-min", 1, NULL, "Only consider symbols equal to or greater than this size." DESC_NEWLINE "The default is 0x00000000."};
+static Switch gMaxSize = {"--max-size", "-max", 1, NULL, "Only consider symbols equal to or smaller than this size." DESC_NEWLINE "The default is 0xFFFFFFFF."};
+static Switch gMatchScope = {"--match-scope", "-msco", 1, NULL, "Only consider scopes that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify a range of scopes," DESC_NEWLINE "though PUBLIC, STATIC, and UNDEF are your only choices."};
+static Switch gMatchClass = {"--match-class", "-mcla", 1, NULL, "Only consider classes that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify a range of classes," DESC_NEWLINE "though CODE and DATA are your only choices."};
+static Switch gMatchModule = {"--match-module", "-mmod", 1, NULL, "Only consider modules that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify an array of modules."};
+static Switch gMatchSection = {"--match-section", "-msec", 1, NULL, "Only consider sections that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify an array of sections."  DESC_NEWLINE "Section is considered symbol type."};
+static Switch gMatchObject = {"--match-object", "-mobj", 1, NULL, "Only consider objects that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify an array of objects."};
+static Switch gMatchSymbol = {"--match-symbol", "-msym", 1, NULL, "Only consider symbols that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify an array of symbols."};
+
+static Switch* gSwitches[] = {
+        &gInputSwitch,
+        &gOutputSwitch,
+        &gModuleSwitch,
+        &gTotalSwitch,
+        &gMinSize,
+        &gMaxSize,
+        &gMatchClass,
+        &gMatchScope,
+        &gMatchModule,
+        &gMatchSection,
+        &gMatchObject,
+        &gMatchSymbol,
+        &gHelpSwitch
+};
+
+
+typedef struct __struct_SizeStats
+/*
+**  Track totals.
+**
+**  mData       Size of data.
+**  mCode       Size of code.
+*/
+{
+    unsigned long mData;
+    unsigned long mCode;
+}
+SizeStats;
+
+
+typedef struct __struct_ModuleStats
+/*
+**  Track module level information.
+**
+**  mModule     Module name.
+**  mSize       Size of module.
+*/
+{
+    char* mModule;
+    SizeStats mSize;
+}
+ModuleStats;
+
+typedef enum __enum_SegmentClass
+{
+        CODE,
+        DATA
+}
+SegmentClass;
+
+
+static int moduleCompare(const void* in1, const void* in2)
+/*
+**  qsort helper function.
+*/
+{
+    int retval = 0;
+
+    const ModuleStats* one = (const ModuleStats*)in1;
+    const ModuleStats* two = (const ModuleStats*)in2;
+    unsigned long oneSize = one->mSize.mCode + one->mSize.mData;
+    unsigned long twoSize = two->mSize.mCode + two->mSize.mData;
+
+    if(oneSize < twoSize)
+    {
+        retval = 1;
+    }
+    else if(oneSize > twoSize)
+    {
+        retval = -1;
+    }
+
+    return retval;
+}
+
+
+void trimWhite(char* inString)
+/*
+**  Remove any whitespace from the end of the string.
+*/
+{
+    int len = strlen(inString);
+
+    while(len)
+    {
+        len--;
+
+        if(isspace(*(inString + len)))
+        {
+            *(inString + len) = '\0';
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+
+int codesighs(Options* inOptions)
+/*
+**  Output a simplistic report based on our options.
+*/
+{
+    int retval = 0;
+    char lineBuffer[0x1000];
+    int scanRes = 0;
+    unsigned long size;
+    char segClass[0x10];
+    char scope[0x10];
+    char module[0x100];
+    char segment[0x40];
+    char object[0x100];
+    char* symbol;
+    SizeStats overall;
+    ModuleStats* modules = NULL;
+    unsigned moduleCount = 0;
+
+    memset(&overall, 0, sizeof(overall));
+
+    /*
+    **  Read the file line by line, regardless of number of fields.
+    **  We assume tab separated value formatting, at least 7 lead values:
+    **      size class scope module segment object symbol ....
+    */
+    while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
+    {
+        trimWhite(lineBuffer);
+
+        scanRes = sscanf(lineBuffer,
+            "%x\t%s\t%s\t%s\t%s\t%s\t",
+            (unsigned*)&size,
+            segClass,
+            scope,
+            module,
+            segment,
+            object);
+
+        if(6 == scanRes)
+        {
+            SegmentClass segmentClass = CODE;
+
+            symbol = strchr(lineBuffer, '\t') + 1;
+
+            /*
+            **  Qualify the segment class.
+            */
+            if(0 == strcmp(segClass, "DATA"))
+            {
+                segmentClass = DATA;
+            }
+            else if(0 == strcmp(segClass, "CODE"))
+            {
+                segmentClass = CODE;
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, segClass, "Unable to determine segment class.");
+            }
+
+            if(0 == retval)
+            {
+                /*
+                **  Match any options required before continuing.
+                **  This is where you would want to add more restrictive totalling.
+                */
+
+                /*
+                **  Match size.
+                */
+                if(size < inOptions->mMinSize)
+                {
+                    continue;
+                }
+                if(size > inOptions->mMaxSize)
+                {
+                    continue;
+                }
+
+                /*
+                **  Match class.
+                */
+                if(0 != inOptions->mMatchClassCount)
+                {
+                    unsigned loop = 0;
+
+                    for(loop = 0; loop < inOptions->mMatchClassCount; loop++)
+                    {
+                        if(NULL != strstr(segClass, inOptions->mMatchClasses[loop]))
+                        {
+                            break;
+                        }
+                    }
+
+                    /*
+                    **  If there was no match, we skip the line.
+                    */
+                    if(loop == inOptions->mMatchClassCount)
+                    {
+                        continue;
+                    }
+                }
+
+                /*
+                **  Match scope.
+                */
+                if(0 != inOptions->mMatchScopeCount)
+                {
+                    unsigned loop = 0;
+
+                    for(loop = 0; loop < inOptions->mMatchScopeCount; loop++)
+                    {
+                        if(NULL != strstr(scope, inOptions->mMatchScopes[loop]))
+                        {
+                            break;
+                        }
+                    }
+
+                    /*
+                    **  If there was no match, we skip the line.
+                    */
+                    if(loop == inOptions->mMatchScopeCount)
+                    {
+                        continue;
+                    }
+                }
+
+                /*
+                **  Match modules.
+                */
+                if(0 != inOptions->mMatchModuleCount)
+                {
+                    unsigned loop = 0;
+
+                    for(loop = 0; loop < inOptions->mMatchModuleCount; loop++)
+                    {
+                        if(NULL != strstr(module, inOptions->mMatchModules[loop]))
+                        {
+                            break;
+                        }
+                    }
+
+                    /*
+                    **  If there was no match, we skip the line.
+                    */
+                    if(loop == inOptions->mMatchModuleCount)
+                    {
+                        continue;
+                    }
+                }
+
+                /*
+                **  Match sections.
+                */
+                if(0 != inOptions->mMatchSectionCount)
+                {
+                    unsigned loop = 0;
+
+                    for(loop = 0; loop < inOptions->mMatchSectionCount; loop++)
+                    {
+                        if(NULL != strstr(segment, inOptions->mMatchSections[loop]))
+                        {
+                            break;
+                        }
+                    }
+
+                    /*
+                    **  If there was no match, we skip the line.
+                    */
+                    if(loop == inOptions->mMatchSectionCount)
+                    {
+                        continue;
+                    }
+                }
+
+                /*
+                **  Match object.
+                */
+                if(0 != inOptions->mMatchObjectCount)
+                {
+                    unsigned loop = 0;
+
+                    for(loop = 0; loop < inOptions->mMatchObjectCount; loop++)
+                    {
+                        if(NULL != strstr(object, inOptions->mMatchObjects[loop]))
+                        {
+                            break;
+                        }
+                    }
+
+                    /*
+                    **  If there was no match, we skip the line.
+                    */
+                    if(loop == inOptions->mMatchObjectCount)
+                    {
+                        continue;
+                    }
+                }
+
+                /*
+                **  Match symbols.
+                */
+                if(0 != inOptions->mMatchSymbolCount)
+                {
+                    unsigned loop = 0;
+
+                    for(loop = 0; loop < inOptions->mMatchSymbolCount; loop++)
+                    {
+                        if(NULL != strstr(symbol, inOptions->mMatchSymbols[loop]))
+                        {
+                            break;
+                        }
+                    }
+
+                    /*
+                    **  If there was no match, we skip the line.
+                    */
+                    if(loop == inOptions->mMatchSymbolCount)
+                    {
+                        continue;
+                    }
+                }
+
+                /*
+                **  Update overall totals.
+                */
+                if(CODE == segmentClass)
+                {
+                    overall.mCode += size;
+                }
+                else if(DATA == segmentClass)
+                {
+                    overall.mData += size;
+                }
+
+                /*
+                **  See what else we should be tracking.
+                */
+                if(0 == inOptions->mTotalOnly)
+                {
+                    if(inOptions->mModules)
+                    {
+                        unsigned index = 0;
+                        
+                        /*
+                        **  Find the module to modify.
+                        */
+                        for(index = 0; index < moduleCount; index++)
+                        {
+                            if(0 == strcmp(modules[index].mModule, module))
+                            {
+                                break;
+                            }
+                        }
+                        
+                        /*
+                        **  If the index is the same as the count, we need to
+                        **      add a new module.
+                        */
+                        if(index == moduleCount)
+                        {
+                            void* moved = NULL;
+                            
+                            moved = realloc(modules, sizeof(ModuleStats) * (moduleCount + 1));
+                            if(NULL != moved)
+                            {
+                                modules = (ModuleStats*)moved;
+                                moduleCount++;
+                                
+                                memset(modules + index, 0, sizeof(ModuleStats));
+                                modules[index].mModule = strdup(module);
+                                if(NULL == modules[index].mModule)
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, module, "Unable to duplicate string.");
+                                }
+                            }
+                            else
+                            {
+                                retval = __LINE__;
+                                ERROR_REPORT(retval, inOptions->mProgramName, "Unable to allocate module memory.");
+                            }
+                        }
+                        
+                        if(0 == retval)
+                        {
+                            if(CODE == segmentClass)
+                            {
+                                modules[index].mSize.mCode += size;
+                            }
+                            else if(DATA == segmentClass)
+                            {
+                                modules[index].mSize.mData += size;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            retval = __LINE__;
+            ERROR_REPORT(retval, inOptions->mInputName, "Problem extracting values from file.");
+        }
+    }
+
+    if(0 == retval && 0 != ferror(inOptions->mInput))
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
+    }
+
+    /*
+    **  If all went well, time to report.
+    */
+    if(0 == retval)
+    {
+        if(inOptions->mTotalOnly)
+        {
+            fprintf(inOptions->mOutput, "%u\n", (unsigned)(overall.mCode + overall.mData));
+        }
+        else
+        {
+            fprintf(inOptions->mOutput, "Overall Size\n");
+            fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", (unsigned)(overall.mCode + overall.mData));
+            fprintf(inOptions->mOutput, "\tCode:\t%10u\n", (unsigned)overall.mCode);
+            fprintf(inOptions->mOutput, "\tData:\t%10u\n", (unsigned)overall.mData);
+        }
+
+        /*
+        **  Check options to see what else we should output.
+        */
+        if(inOptions->mModules && moduleCount)
+        {
+            unsigned loop = 0;
+
+            /*
+            **  Sort the modules by their size.
+            */
+            qsort(modules, (size_t)moduleCount, sizeof(ModuleStats), moduleCompare);
+
+            /*
+            **  Output each one.
+            **  Might as well clean up while we go too.
+            */
+            for(loop = 0; loop < moduleCount; loop++)
+            {
+                fprintf(inOptions->mOutput, "\n");
+                fprintf(inOptions->mOutput, "%s\n", modules[loop].mModule);
+                fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", (unsigned)(modules[loop].mSize.mCode + modules[loop].mSize.mData));
+                fprintf(inOptions->mOutput, "\tCode:\t%10u\n", (unsigned)modules[loop].mSize.mCode);
+                fprintf(inOptions->mOutput, "\tData:\t%10u\n", (unsigned)modules[loop].mSize.mData);
+
+                CLEANUP(modules[loop].mModule);
+            }
+
+            /*
+            **  Done with modules.
+            */
+            CLEANUP(modules);
+            moduleCount = 0;
+        }
+    }
+
+    return retval;
+}
+
+
+int initOptions(Options* outOptions, int inArgc, char** inArgv)
+/*
+**  returns int     0 if successful.
+*/
+{
+    int retval = 0;
+    int loop = 0;
+    int switchLoop = 0;
+    int match = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    Switch* current = NULL;
+
+    /*
+    **  Set any defaults.
+    */
+    memset(outOptions, 0, sizeof(Options));
+    outOptions->mProgramName = inArgv[0];
+    outOptions->mInput = stdin;
+    outOptions->mInputName = strdup("stdin");
+    outOptions->mOutput = stdout;
+    outOptions->mOutputName = strdup("stdout");
+    outOptions->mMaxSize = 0xFFFFFFFFU;
+
+    if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
+    }
+
+    /*
+    **  Go through and attempt to do the right thing.
+    */
+    for(loop = 1; loop < inArgc && 0 == retval; loop++)
+    {
+        match = 0;
+        current = NULL;
+
+        for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
+        {
+            if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+            else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+
+            if(match)
+            {
+                if(gSwitches[switchLoop]->mHasValue)
+                {
+                    /*
+                    **  Attempt to absorb next option to fullfill value.
+                    */
+                    if(loop + 1 < inArgc)
+                    {
+                        loop++;
+
+                        current = gSwitches[switchLoop];
+                        current->mValue = inArgv[loop];
+                    }
+                }
+                else
+                {
+                    current = gSwitches[switchLoop];
+                }
+
+                break;
+            }
+        }
+
+        if(0 == match)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
+        }
+        else if(NULL == current)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
+        }
+        else
+        {
+            /*
+            ** Do something based on address/swtich.
+            */
+            if(current == &gInputSwitch)
+            {
+                CLEANUP(outOptions->mInputName);
+                if(NULL != outOptions->mInput && stdin != outOptions->mInput)
+                {
+                    fclose(outOptions->mInput);
+                    outOptions->mInput = NULL;
+                }
+
+                outOptions->mInput = fopen(current->mValue, "r");
+                if(NULL == outOptions->mInput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
+                }
+                else
+                {
+                    outOptions->mInputName = strdup(current->mValue);
+                    if(NULL == outOptions->mInputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gOutputSwitch)
+            {
+                CLEANUP(outOptions->mOutputName);
+                if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
+                {
+                    fclose(outOptions->mOutput);
+                    outOptions->mOutput = NULL;
+                }
+
+                outOptions->mOutput = fopen(current->mValue, "a");
+                if(NULL == outOptions->mOutput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
+                }
+                else
+                {
+                    outOptions->mOutputName = strdup(current->mValue);
+                    if(NULL == outOptions->mOutputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gHelpSwitch)
+            {
+                outOptions->mHelp = __LINE__;
+            }
+            else if(current == &gModuleSwitch)
+            {
+                outOptions->mModules = __LINE__;
+            }
+            else if(current == &gTotalSwitch)
+            {
+                outOptions->mTotalOnly = __LINE__;
+            }
+            else if(current == &gMinSize)
+            {
+                unsigned long arg = 0;
+                char* endScan = NULL;
+
+                errno = 0;
+                arg = strtoul(current->mValue, &endScan, 0);
+                if(0 == errno && endScan != current->mValue)
+                {
+                    outOptions->mMinSize = arg;
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
+                }
+            }
+            else if(current == &gMaxSize)
+            {
+                unsigned long arg = 0;
+                char* endScan = NULL;
+
+                errno = 0;
+                arg = strtoul(current->mValue, &endScan, 0);
+                if(0 == errno && endScan != current->mValue)
+                {
+                    outOptions->mMaxSize = arg;
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
+                }
+            }
+            else if(current == &gMatchClass)
+            {
+                char* dupMatch = NULL;
+                
+                dupMatch = strdup(current->mValue);
+                if(NULL != dupMatch)
+                {
+                    void* moved = NULL;
+
+                    moved = realloc(outOptions->mMatchClasses, sizeof(char*) * (outOptions->mMatchClassCount + 1));
+                    if(NULL != moved)
+                    {
+                        outOptions->mMatchClasses = (char**)moved;
+                        outOptions->mMatchClasses[outOptions->mMatchClassCount] = dupMatch;
+                        outOptions->mMatchClassCount++;
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
+                    }
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
+                }
+            }
+            else if(current == &gMatchScope)
+            {
+                char* dupMatch = NULL;
+                
+                dupMatch = strdup(current->mValue);
+                if(NULL != dupMatch)
+                {
+                    void* moved = NULL;
+
+                    moved = realloc(outOptions->mMatchScopes, sizeof(char*) * (outOptions->mMatchScopeCount + 1));
+                    if(NULL != moved)
+                    {
+                        outOptions->mMatchScopes = (char**)moved;
+                        outOptions->mMatchScopes[outOptions->mMatchScopeCount] = dupMatch;
+                        outOptions->mMatchScopeCount++;
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
+                    }
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
+                }
+            }
+            else if(current == &gMatchModule)
+            {
+                char* dupMatch = NULL;
+                
+                dupMatch = strdup(current->mValue);
+                if(NULL != dupMatch)
+                {
+                    void* moved = NULL;
+
+                    moved = realloc(outOptions->mMatchModules, sizeof(char*) * (outOptions->mMatchModuleCount + 1));
+                    if(NULL != moved)
+                    {
+                        outOptions->mMatchModules = (char**)moved;
+                        outOptions->mMatchModules[outOptions->mMatchModuleCount] = dupMatch;
+                        outOptions->mMatchModuleCount++;
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
+                    }
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
+                }
+            }
+            else if(current == &gMatchSection)
+            {
+                char* dupMatch = NULL;
+                
+                dupMatch = strdup(current->mValue);
+                if(NULL != dupMatch)
+                {
+                    void* moved = NULL;
+
+                    moved = realloc(outOptions->mMatchSections, sizeof(char*) * (outOptions->mMatchSectionCount + 1));
+                    if(NULL != moved)
+                    {
+                        outOptions->mMatchSections = (char**)moved;
+                        outOptions->mMatchSections[outOptions->mMatchSectionCount] = dupMatch;
+                        outOptions->mMatchSectionCount++;
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
+                    }
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
+                }
+            }
+            else if(current == &gMatchObject)
+            {
+                char* dupMatch = NULL;
+                
+                dupMatch = strdup(current->mValue);
+                if(NULL != dupMatch)
+                {
+                    void* moved = NULL;
+
+                    moved = realloc(outOptions->mMatchObjects, sizeof(char*) * (outOptions->mMatchObjectCount + 1));
+                    if(NULL != moved)
+                    {
+                        outOptions->mMatchObjects = (char**)moved;
+                        outOptions->mMatchObjects[outOptions->mMatchObjectCount] = dupMatch;
+                        outOptions->mMatchObjectCount++;
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
+                    }
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
+                }
+            }
+            else if(current == &gMatchSymbol)
+            {
+                char* dupMatch = NULL;
+                
+                dupMatch = strdup(current->mValue);
+                if(NULL != dupMatch)
+                {
+                    void* moved = NULL;
+
+                    moved = realloc(outOptions->mMatchSymbols, sizeof(char*) * (outOptions->mMatchSymbolCount + 1));
+                    if(NULL != moved)
+                    {
+                        outOptions->mMatchSymbols = (char**)moved;
+                        outOptions->mMatchSymbols[outOptions->mMatchSymbolCount] = dupMatch;
+                        outOptions->mMatchSymbolCount++;
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
+                    }
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
+                }
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+void cleanOptions(Options* inOptions)
+/*
+**  Clean up any open handles.
+*/
+{
+    unsigned loop = 0;
+
+    CLEANUP(inOptions->mInputName);
+    if(NULL != inOptions->mInput && stdin != inOptions->mInput)
+    {
+        fclose(inOptions->mInput);
+    }
+    CLEANUP(inOptions->mOutputName);
+    if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
+    {
+        fclose(inOptions->mOutput);
+    }
+
+    for(loop = 0; loop < inOptions->mMatchClassCount; loop++)
+    {
+        CLEANUP(inOptions->mMatchClasses[loop]);
+    }
+    CLEANUP(inOptions->mMatchClasses);
+
+    for(loop = 0; loop < inOptions->mMatchScopeCount; loop++)
+    {
+        CLEANUP(inOptions->mMatchScopes[loop]);
+    }
+    CLEANUP(inOptions->mMatchScopes);
+
+    for(loop = 0; loop < inOptions->mMatchModuleCount; loop++)
+    {
+        CLEANUP(inOptions->mMatchModules[loop]);
+    }
+    CLEANUP(inOptions->mMatchModules);
+
+    for(loop = 0; loop < inOptions->mMatchSectionCount; loop++)
+    {
+        CLEANUP(inOptions->mMatchSections[loop]);
+    }
+    CLEANUP(inOptions->mMatchSections);
+
+    for(loop = 0; loop < inOptions->mMatchObjectCount; loop++)
+    {
+        CLEANUP(inOptions->mMatchObjects[loop]);
+    }
+    CLEANUP(inOptions->mMatchObjects);
+
+    for(loop = 0; loop < inOptions->mMatchSymbolCount; loop++)
+    {
+        CLEANUP(inOptions->mMatchSymbols[loop]);
+    }
+    CLEANUP(inOptions->mMatchSymbols);
+
+    memset(inOptions, 0, sizeof(Options));
+}
+
+
+void showHelp(Options* inOptions)
+/*
+**  Show some simple help text on usage.
+*/
+{
+    int loop = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    const char* valueText = NULL;
+
+    printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
+    printf("\n");
+    printf("arguments:\n");
+
+    for(loop = 0; loop < switchCount; loop++)
+    {
+        if(gSwitches[loop]->mHasValue)
+        {
+            valueText = " <value>";
+        }
+        else
+        {
+            valueText = "";
+        }
+
+        printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
+        printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
+        printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
+    }
+
+    printf("This tool takes a tsv file and reports composite code and data sizes.\n");
+}
+
+
+int main(int inArgc, char** inArgv)
+{
+    int retval = 0;
+    Options options;
+
+    retval = initOptions(&options, inArgc, inArgv);
+    if(options.mHelp)
+    {
+        showHelp(&options);
+    }
+    else if(0 == retval)
+    {
+        retval = codesighs(&options);
+    }
+
+    cleanOptions(&options);
+    return retval;
+}
+
diff --git a/third_party/codesighs/codesighs.gyp b/third_party/codesighs/codesighs.gyp
new file mode 100644
index 0000000000000..c3874f8d5201d
--- /dev/null
+++ b/third_party/codesighs/codesighs.gyp
@@ -0,0 +1,60 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../build/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'codesighs',
+      'type': 'executable',
+      'sources': [
+        'codesighs.c',
+      ],
+    },
+    {
+      'target_name': 'maptsvdifftool',
+      'type': 'executable',
+      'sources': [
+        'maptsvdifftool.c',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="win"', {
+      'targets': [
+        {
+          'target_name': 'msmap2tsv',
+          'type': 'executable',
+          'sources': [
+            'msmap2tsv.c',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-lDbgHelp.lib',
+            ],
+          },
+        },
+        {
+          'target_name': 'msdump2symdb',
+          'type': 'executable',
+          'sources': [
+            'msdump2symdb.c',
+          ],
+        },
+      ],
+    }, { # else: OS != "windows"
+      'targets': [
+        {
+          'target_name': 'nm2tsv',
+          'type': 'executable',
+          'sources': [
+            'nm2tsv.c',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/third_party/codesighs/maptsvdifftool.c b/third_party/codesighs/maptsvdifftool.c
new file mode 100644
index 0000000000000..82070609ccab5
--- /dev/null
+++ b/third_party/codesighs/maptsvdifftool.c
@@ -0,0 +1,1311 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is maptsvdifftool.c code, released
+ * Oct 3, 2002.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Garrett Arch Blythe, 03-October-2002
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#define ERROR_REPORT(num, val, msg)   fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
+#define CLEANUP(ptr)    do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
+
+
+typedef struct __struct_Options
+/*
+**  Options to control how we perform.
+**
+**  mProgramName    Used in help text.
+**  mInput          File to read for input.
+**                  Default is stdin.
+**  mInputName      Name of the file.
+**  mOutput         Output file, append.
+**                  Default is stdout.
+**  mOutputName     Name of the file.
+**  mHelp           Whether or not help should be shown.
+**  mSummaryOnly    Only output a signle line.
+**  mZeroDrift      Output zero drift data.
+**  mNegation       Perform negation heuristics on the symbol drifts.
+*/
+{
+    const char* mProgramName;
+    FILE* mInput;
+    char* mInputName;
+    FILE* mOutput;
+    char* mOutputName;
+    int mHelp;
+    int mSummaryOnly;
+    int mZeroDrift;
+    int mNegation;
+}
+Options;
+
+
+typedef struct __struct_Switch
+/*
+**  Command line options.
+*/
+{
+    const char* mLongName;
+    const char* mShortName;
+    int mHasValue;
+    const char* mValue;
+    const char* mDescription;
+}
+Switch;
+
+#define DESC_NEWLINE "\n\t\t"
+
+static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
+static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
+static Switch gSummarySwitch = {"--summary", "-s", 0, NULL, "Only output a single line." DESC_NEWLINE "The cumulative size changes." DESC_NEWLINE "Overrides all other output options."};
+static Switch gZeroDriftSwitch = {"--zerodrift", "-z", 0, NULL, "Output zero drift data." DESC_NEWLINE "Reports symbol changes even when there is no net drift."};
+static Switch gNegationSwitch = {"--negation", "-n", 0, NULL, "Use negation heuristics." DESC_NEWLINE "When symbol sizes are inferred by offset, order changes cause noise." DESC_NEWLINE "This helps see through the noise by eliminating equal and opposite drifts."};
+static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
+
+static Switch* gSwitches[] = {
+        &gInputSwitch,
+        &gOutputSwitch,
+        &gSummarySwitch,
+        &gZeroDriftSwitch,
+        &gNegationSwitch,
+        &gHelpSwitch
+};
+
+
+typedef struct __struct_SizeComposition
+/*
+**  Used to keep which parts positive and negative resulted in the total.
+*/
+{
+    int mPositive;
+    int mNegative;
+}
+SizeComposition;
+
+
+typedef struct __struct_SizeStats
+/*
+**  Keep track of sizes.
+**  Use signed integers so that negatives are valid, in which case we shrunk.
+*/
+{
+    int mCode;
+    SizeComposition mCodeComposition;
+
+    int mData;
+    SizeComposition mDataComposition;
+}
+SizeStats;
+
+
+typedef enum __enum_SegmentClass
+/*
+**  What type of data a segment holds.
+*/
+{
+        CODE,
+        DATA
+}
+SegmentClass;
+
+
+typedef struct __struct_SymbolStats
+/*
+**  Symbol level stats.
+*/
+{
+    char* mSymbol;
+    int mSize;
+}
+SymbolStats;
+
+
+typedef struct __struct_ObjectStats
+/*
+**  Object level stats.
+*/
+{
+    char* mObject;
+    int mSize;
+    SizeComposition mComposition;
+    SymbolStats* mSymbols;
+    unsigned mSymbolCount;
+}
+ObjectStats;
+
+
+typedef struct __struct_SegmentStats
+/*
+**  Segment level stats.
+*/
+{
+    char* mSegment;
+    SegmentClass mClass;
+    int mSize;
+    SizeComposition mComposition;
+    ObjectStats* mObjects;
+    unsigned mObjectCount;
+}
+SegmentStats;
+
+
+typedef struct __struct_ModuleStats
+/*
+**  Module level stats.
+*/
+{
+    char* mModule;
+    SizeStats mSize;
+    SegmentStats* mSegments;
+    unsigned mSegmentCount;
+}
+ModuleStats;
+
+
+static int moduleCompare(const void* in1, const void* in2)
+/*
+**  qsort helper.
+*/
+{
+    int retval = 0;
+
+    ModuleStats* one = (ModuleStats*)in1;
+    ModuleStats* two = (ModuleStats*)in2;
+
+    int oneSize = (one->mSize.mCode + one->mSize.mData);
+    int twoSize = (two->mSize.mCode + two->mSize.mData);
+
+    if(oneSize < twoSize)
+    {
+        retval = 1;
+    }
+    else if(oneSize > twoSize)
+    {
+        retval = -1;
+    }
+    else
+    {
+        retval = strcmp(one->mModule, two->mModule);
+        if(0 > oneSize && 0 > twoSize)
+        {
+            retval *= -1;
+        }
+    }
+
+    return retval;
+}
+
+
+static int segmentCompare(const void* in1, const void* in2)
+/*
+**  qsort helper.
+*/
+{
+    int retval = 0;
+
+    SegmentStats* one = (SegmentStats*)in1;
+    SegmentStats* two = (SegmentStats*)in2;
+
+    if(one->mSize < two->mSize)
+    {
+        retval = 1;
+    }
+    else if(one->mSize > two->mSize)
+    {
+        retval = -1;
+    }
+    else
+    {
+        retval = strcmp(one->mSegment, two->mSegment);
+        if(0 > one->mSize && 0 > two->mSize)
+        {
+            retval *= -1;
+        }
+    }
+
+    return retval;
+}
+
+
+static int objectCompare(const void* in1, const void* in2)
+/*
+**  qsort helper.
+*/
+{
+    int retval = 0;
+
+    ObjectStats* one = (ObjectStats*)in1;
+    ObjectStats* two = (ObjectStats*)in2;
+
+    if(one->mSize < two->mSize)
+    {
+        retval = 1;
+    }
+    else if(one->mSize > two->mSize)
+    {
+        retval = -1;
+    }
+    else
+    {
+        retval = strcmp(one->mObject, two->mObject);
+        if(0 > one->mSize && 0 > two->mSize)
+        {
+            retval *= -1;
+        }
+    }
+
+    return retval;
+}
+
+
+static int symbolCompare(const void* in1, const void* in2)
+/*
+**  qsort helper.
+*/
+{
+    int retval = 0;
+
+    SymbolStats* one = (SymbolStats*)in1;
+    SymbolStats* two = (SymbolStats*)in2;
+
+    if(one->mSize < two->mSize)
+    {
+        retval = 1;
+    }
+    else if(one->mSize > two->mSize)
+    {
+        retval = -1;
+    }
+    else
+    {
+        retval = strcmp(one->mSymbol, two->mSymbol);
+        if(0 > one->mSize && 0 > two->mSize)
+        {
+            retval *= -1;
+        }
+    }
+
+    return retval;
+}
+
+
+void trimWhite(char* inString)
+/*
+**  Remove any whitespace from the end of the string.
+*/
+{
+    int len = strlen(inString);
+
+    while(len)
+    {
+        len--;
+
+        if(isspace(*(inString + len)))
+        {
+            *(inString + len) = '\0';
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+
+int difftool(Options* inOptions)
+/*
+**  Read a diff file and spit out relevant information.
+*/
+{
+    int retval = 0;
+    char lineBuffer[0x500];
+    SizeStats overall;
+    ModuleStats* modules = NULL;
+    unsigned moduleCount = 0;
+    unsigned moduleLoop = 0;
+    ModuleStats* theModule = NULL;
+    unsigned segmentLoop = 0;
+    SegmentStats* theSegment = NULL;
+    unsigned objectLoop = 0;
+    ObjectStats* theObject = NULL;
+    unsigned symbolLoop = 0;
+    SymbolStats* theSymbol = NULL;
+    unsigned allSymbolCount = 0;
+
+    memset(&overall, 0, sizeof(overall));
+
+    /*
+    **  Read the entire diff file.
+    **  We're only interested in lines beginning with < or >
+    */
+    while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
+    {
+        trimWhite(lineBuffer);
+
+        if(('<' == lineBuffer[0] || '>' == lineBuffer[0]) && ' ' == lineBuffer[1])
+        {
+            int additive = 0;
+            char* theLine = &lineBuffer[2];
+            int scanRes = 0;
+            int size;
+            char segClass[0x10];
+            char scope[0x10];
+            char module[0x100];
+            char segment[0x40];
+            char object[0x100];
+            char* symbol = NULL;
+
+            /*
+            **  Figure out if the line adds or subtracts from something.
+            */
+            if('>' == lineBuffer[0])
+            {
+                additive = __LINE__;
+            }
+
+
+            /*
+            **  Scan the line for information.
+            */
+            scanRes = sscanf(theLine,
+                "%x\t%s\t%s\t%s\t%s\t%s\t",
+                (unsigned*)&size,
+                segClass,
+                scope,
+                module,
+                segment,
+                object);
+
+            if(6 == scanRes)
+            {
+                SegmentClass segmentClass = DATA;
+
+                symbol = strrchr(theLine, '\t') + 1;
+
+                if(0 == strcmp(segClass, "CODE"))
+                {
+                    segmentClass = CODE;
+                }
+                else if(0 == strcmp(segClass, "DATA"))
+                {
+                    segmentClass = DATA;
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, segClass, "Unable to determine segment class.");
+                }
+
+                if(0 == retval)
+                {
+                    unsigned moduleIndex = 0;
+
+                    /*
+                    **  Find, in succession, the following things:
+                    **      the module
+                    **      the segment
+                    **      the object
+                    **      the symbol
+                    **  Failure to find any one of these means to create it.
+                    */
+                    
+                    for(moduleIndex = 0; moduleIndex < moduleCount; moduleIndex++)
+                    {
+                        if(0 == strcmp(modules[moduleIndex].mModule, module))
+                        {
+                            break;
+                        }
+                    }
+                    
+                    if(moduleIndex == moduleCount)
+                    {
+                        void* moved = NULL;
+                        
+                        moved = realloc(modules, sizeof(ModuleStats) * (1 + moduleCount));
+                        if(NULL != moved)
+                        {
+                            modules = (ModuleStats*)moved;
+                            moduleCount++;
+                            memset(modules + moduleIndex, 0, sizeof(ModuleStats));
+                            
+                            modules[moduleIndex].mModule = strdup(module);
+                            if(NULL == modules[moduleIndex].mModule)
+                            {
+                                retval = __LINE__;
+                                ERROR_REPORT(retval, module, "Unable to duplicate string.");
+                            }
+                        }
+                        else
+                        {
+                            retval = __LINE__;
+                            ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase module array.");
+                        }
+                    }
+                    
+                    if(0 == retval)
+                    {
+                        unsigned segmentIndex = 0;
+                        theModule = (modules + moduleIndex);
+                        
+                        for(segmentIndex = 0; segmentIndex < theModule->mSegmentCount; segmentIndex++)
+                        {
+                            if(0 == strcmp(segment, theModule->mSegments[segmentIndex].mSegment))
+                            {
+                                break;
+                            }
+                        }
+                        
+                        if(segmentIndex == theModule->mSegmentCount)
+                        {
+                            void* moved = NULL;
+                            
+                            moved = realloc(theModule->mSegments, sizeof(SegmentStats) * (theModule->mSegmentCount + 1));
+                            if(NULL != moved)
+                            {
+                                theModule->mSegments = (SegmentStats*)moved;
+                                theModule->mSegmentCount++;
+                                memset(theModule->mSegments + segmentIndex, 0, sizeof(SegmentStats));
+                                
+                                theModule->mSegments[segmentIndex].mClass = segmentClass;
+                                theModule->mSegments[segmentIndex].mSegment = strdup(segment);
+                                if(NULL == theModule->mSegments[segmentIndex].mSegment)
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, segment, "Unable to duplicate string.");
+                                }
+                            }
+                            else
+                            {
+                                retval = __LINE__;
+                                ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase segment array.");
+                            }
+                        }
+                        
+                        if(0 == retval)
+                        {
+                            unsigned objectIndex = 0;
+                            theSegment = (theModule->mSegments + segmentIndex);
+                            
+                            for(objectIndex = 0; objectIndex < theSegment->mObjectCount; objectIndex++)
+                            {
+                                if(0 == strcmp(object, theSegment->mObjects[objectIndex].mObject))
+                                {
+                                    break;
+                                }
+                            }
+                            
+                            if(objectIndex == theSegment->mObjectCount)
+                            {
+                                void* moved = NULL;
+                                
+                                moved = realloc(theSegment->mObjects, sizeof(ObjectStats) * (1 + theSegment->mObjectCount));
+                                if(NULL != moved)
+                                {
+                                    theSegment->mObjects = (ObjectStats*)moved;
+                                    theSegment->mObjectCount++;
+                                    memset(theSegment->mObjects + objectIndex, 0, sizeof(ObjectStats));
+                                    
+                                    theSegment->mObjects[objectIndex].mObject = strdup(object);
+                                    if(NULL == theSegment->mObjects[objectIndex].mObject)
+                                    {
+                                        retval = __LINE__;
+                                        ERROR_REPORT(retval, object, "Unable to duplicate string.");
+                                    }
+                                }
+                                else
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase object array.");
+                                }
+                            }
+                            
+                            if(0 == retval)
+                            {
+                                unsigned symbolIndex = 0;
+                                theObject = (theSegment->mObjects + objectIndex);
+                                
+                                for(symbolIndex = 0; symbolIndex < theObject->mSymbolCount; symbolIndex++)
+                                {
+                                    if(0 == strcmp(symbol, theObject->mSymbols[symbolIndex].mSymbol))
+                                    {
+                                        break;
+                                    }
+                                }
+                                
+                                if(symbolIndex == theObject->mSymbolCount)
+                                {
+                                    void* moved = NULL;
+                                    
+                                    moved = realloc(theObject->mSymbols, sizeof(SymbolStats) * (1 + theObject->mSymbolCount));
+                                    if(NULL != moved)
+                                    {
+                                        theObject->mSymbols = (SymbolStats*)moved;
+                                        theObject->mSymbolCount++;
+                                        allSymbolCount++;
+                                        memset(theObject->mSymbols + symbolIndex, 0, sizeof(SymbolStats));
+                                        
+                                        theObject->mSymbols[symbolIndex].mSymbol = strdup(symbol);
+                                        if(NULL == theObject->mSymbols[symbolIndex].mSymbol)
+                                        {
+                                            retval = __LINE__;
+                                            ERROR_REPORT(retval, symbol, "Unable to duplicate string.");
+                                        }
+                                    }
+                                    else
+                                    {
+                                        retval = __LINE__;
+                                        ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase symbol array.");
+                                    }
+                                }
+                                
+                                if(0 == retval)
+                                {
+                                    theSymbol = (theObject->mSymbols + symbolIndex);
+
+                                    /*
+                                    **  Update our various totals.
+                                    */
+                                    if(additive)
+                                    {
+                                        if(CODE == segmentClass)
+                                        {
+                                            overall.mCode += size;
+                                            theModule->mSize.mCode += size;
+                                        }
+                                        else if(DATA == segmentClass)
+                                        {
+                                            overall.mData += size;
+                                            theModule->mSize.mData += size;
+                                        }
+
+                                        theSegment->mSize += size;
+                                        theObject->mSize += size;
+                                        theSymbol->mSize += size;
+                                    }
+                                    else
+                                    {
+                                        if(CODE == segmentClass)
+                                        {
+                                            overall.mCode -= size;
+                                            theModule->mSize.mCode -= size;
+                                        }
+                                        else if(DATA == segmentClass)
+                                        {
+                                            overall.mData -= size;
+                                            theModule->mSize.mData -= size;
+                                        }
+
+                                        theSegment->mSize -= size;
+                                        theObject->mSize -= size;
+                                        theSymbol->mSize -= size;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, inOptions->mInputName, "Unable to scan line data.");
+            }
+        }
+    }
+
+    if(0 == retval && 0 != ferror(inOptions->mInput))
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
+    }
+
+    /*
+    **  Next, it is time to perform revisionist history of sorts.
+    **  If the negation switch is in play, we perfrom the following
+    **      aggressive steps:
+    **
+    **  For each section, find size changes which have an equal and
+    **      opposite change, and set them both to zero.
+    **  However, you can only do this if the number of negating changes
+    **      is even, as if it is odd, then any one of the many could be
+    **      at fault for the actual change.
+    **
+    **  This orginally exists to make the win32 codesighs reports more
+    **      readable/meaningful.
+    */
+    if(0 == retval && 0 != inOptions->mNegation)
+    {
+        ObjectStats** objArray = NULL;
+        SymbolStats** symArray = NULL;
+
+        /*
+        **  Create arrays big enough to hold all symbols.
+        **  As well as an array to keep the owning object at the same index.
+        **  We will keep the object around as we may need to modify the size.
+        */
+        objArray = (ObjectStats**)malloc(allSymbolCount * sizeof(ObjectStats*));
+        symArray = (SymbolStats**)malloc(allSymbolCount * sizeof(SymbolStats*));
+        if(NULL == objArray || NULL == symArray)
+        {
+            retval = __LINE__;
+            ERROR_REPORT(retval, inOptions->mProgramName, "Unable to allocate negation array memory.");
+        }
+        else
+        {
+            unsigned arrayCount = 0;
+            unsigned arrayLoop = 0;
+
+            /*
+            **  Go through and perform the steps on each section/segment.
+            */
+            for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
+            {
+                theModule = modules + moduleLoop;
+
+                for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
+                {
+                    theSegment = theModule->mSegments + segmentLoop;
+
+                    /*
+                    **  Collect all symbols under this section.
+                    **  The symbols are spread out between all the objects,
+                    **      so keep track of both independently at the
+                    **      same index.
+                    */
+                    arrayCount = 0;
+
+                    for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
+                    {
+                        theObject = theSegment->mObjects + objectLoop;
+
+                        for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
+                        {
+                            theSymbol = theObject->mSymbols + symbolLoop;
+
+                            objArray[arrayCount] = theObject;
+                            symArray[arrayCount] = theSymbol;
+                            arrayCount++;
+                        }
+                    }
+
+                    /*
+                    **  Now that we have a list of symbols, go through each
+                    **      and see if there is a chance of negation.
+                    */
+                    for(arrayLoop = 0; arrayLoop < arrayCount; arrayLoop++)
+                    {
+                        /*
+                        **  If the item is NULL, it was already negated.
+                        **  Don't do this for items with a zero size.
+                        */
+                        if(NULL != symArray[arrayLoop] && 0 != symArray[arrayLoop]->mSize)
+                        {
+                            unsigned identicalValues = 0;
+                            unsigned oppositeValues = 0;
+                            unsigned lookLoop = 0;
+                            const int lookingFor = symArray[arrayLoop]->mSize;
+
+                            /*
+                            **  Count the number of items with this value.
+                            **  Count the number of items with the opposite equal value.
+                            **  If they are equal, go through and negate all sizes.
+                            */
+                            for(lookLoop = arrayLoop; lookLoop < arrayCount; lookLoop++)
+                            {
+                                /*
+                                **  Skip negated items.
+                                **  Skip zero length items.
+                                */
+                                if(NULL == symArray[lookLoop] || 0 == symArray[lookLoop]->mSize)
+                                {
+                                    continue;
+                                }
+
+                                if(lookingFor == symArray[lookLoop]->mSize)
+                                {
+                                    identicalValues++;
+                                }
+                                else if((-1 * lookingFor) == symArray[lookLoop]->mSize)
+                                {
+                                    oppositeValues++;
+                                }
+                            }
+                            
+                            if(0 != identicalValues && identicalValues == oppositeValues)
+                            {
+                                unsigned negationLoop = 0;
+
+                                for(negationLoop = arrayLoop; 0 != identicalValues || 0 != oppositeValues; negationLoop++)
+                                {
+                                    /*
+                                    **  Skip negated items.
+                                    **  Skip zero length items.
+                                    */
+                                    if(NULL == symArray[negationLoop] || 0 == symArray[negationLoop]->mSize)
+                                    {
+                                        continue;
+                                    }
+
+                                    /*
+                                    **  Negate any size matches.
+                                    **  Reflect the change in the object as well.
+                                    **  Clear the symbol.
+                                    */
+                                    if(lookingFor == symArray[negationLoop]->mSize)
+                                    {
+                                        objArray[negationLoop]->mSize -= lookingFor;
+                                        symArray[negationLoop]->mSize = 0;
+                                        symArray[negationLoop] = NULL;
+
+                                        identicalValues--;
+                                    }
+                                    else if((-1 * lookingFor) == symArray[negationLoop]->mSize)
+                                    {
+                                        objArray[negationLoop]->mSize += lookingFor;
+                                        symArray[negationLoop]->mSize = 0;
+                                        symArray[negationLoop] = NULL;
+
+                                        oppositeValues--;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        CLEANUP(objArray);
+        CLEANUP(symArray);
+    }
+
+
+    /*
+    **  If all went well, time to report.
+    */
+    if(0 == retval)
+    {
+        /*
+        **  Loop through our data once more, so that the symbols can
+        **      propigate their changes upwards in a positive/negative
+        **      fashion.
+        **  This will help give the composite change more meaning.
+        */
+        for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
+        {
+            theModule = modules + moduleLoop;
+            
+            /*
+            **  Skip if there is zero drift, or no net change.
+            */
+            if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode + theModule->mSize.mData))
+            {
+                continue;
+            }
+
+            for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
+            {
+                theSegment = theModule->mSegments + segmentLoop;
+                
+                /*
+                **  Skip if there is zero drift, or no net change.
+                */
+                if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize)
+                {
+                    continue;
+                }
+                
+                for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
+                {
+                    theObject = theSegment->mObjects + objectLoop;
+                    
+                    /*
+                    **  Skip if there is zero drift, or no net change.
+                    */
+                    if(0 == inOptions->mZeroDrift && 0 == theObject->mSize)
+                    {
+                        continue;
+                    }
+
+                    for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
+                    {
+                        theSymbol = theObject->mSymbols + symbolLoop;
+                        
+                        /*
+                        **  Propagate the composition all the way to the top.
+                        **  Sizes of zero change are skipped.
+                        */
+                        if(0 < theSymbol->mSize)
+                        {
+                            theObject->mComposition.mPositive += theSymbol->mSize;
+                            theSegment->mComposition.mPositive += theSymbol->mSize;
+                            if(CODE == theSegment->mClass)
+                            {
+                                overall.mCodeComposition.mPositive += theSymbol->mSize;
+                                theModule->mSize.mCodeComposition.mPositive += theSymbol->mSize;
+                            }
+                            else if(DATA == theSegment->mClass)
+                            {
+                                overall.mDataComposition.mPositive += theSymbol->mSize;
+                                theModule->mSize.mDataComposition.mPositive += theSymbol->mSize;
+                            }
+                        }
+                        else if(0 > theSymbol->mSize)
+                        {
+                            theObject->mComposition.mNegative += theSymbol->mSize;
+                            theSegment->mComposition.mNegative += theSymbol->mSize;
+                            if(CODE == theSegment->mClass)
+                            {
+                                overall.mCodeComposition.mNegative += theSymbol->mSize;
+                                theModule->mSize.mCodeComposition.mNegative += theSymbol->mSize;
+                            }
+                            else if(DATA == theSegment->mClass)
+                            {
+                                overall.mDataComposition.mNegative += theSymbol->mSize;
+                                theModule->mSize.mDataComposition.mNegative += theSymbol->mSize;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+
+        if(inOptions->mSummaryOnly)
+        {
+            fprintf(inOptions->mOutput, "%+d (%+d/%+d)\n", overall.mCode + overall.mData, overall.mCodeComposition.mPositive + overall.mDataComposition.mPositive, overall.mCodeComposition.mNegative + overall.mDataComposition.mNegative);
+        }
+        else
+        {
+            fprintf(inOptions->mOutput, "Overall Change in Size\n");
+            fprintf(inOptions->mOutput, "\tTotal:\t%+11d (%+d/%+d)\n", overall.mCode + overall.mData, overall.mCodeComposition.mPositive + overall.mDataComposition.mPositive, overall.mCodeComposition.mNegative + overall.mDataComposition.mNegative);
+            fprintf(inOptions->mOutput, "\tCode:\t%+11d (%+d/%+d)\n", overall.mCode, overall.mCodeComposition.mPositive, overall.mCodeComposition.mNegative);
+            fprintf(inOptions->mOutput, "\tData:\t%+11d (%+d/%+d)\n", overall.mData, overall.mDataComposition.mPositive, overall.mDataComposition.mNegative);
+        }
+
+        /*
+        **  Check what else we should output.
+        */
+        if(0 == inOptions->mSummaryOnly && NULL != modules && moduleCount)
+        {
+            const char* segmentType = NULL;
+
+            /*
+            **  We're going to sort everything.
+            */
+            qsort(modules, moduleCount, sizeof(ModuleStats), moduleCompare);
+            for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
+            {
+                theModule = modules + moduleLoop;
+
+                qsort(theModule->mSegments, theModule->mSegmentCount, sizeof(SegmentStats), segmentCompare);
+
+                for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
+                {
+                    theSegment = theModule->mSegments + segmentLoop;
+
+                    qsort(theSegment->mObjects, theSegment->mObjectCount, sizeof(ObjectStats), objectCompare);
+
+                    for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
+                    {
+                        theObject = theSegment->mObjects + objectLoop;
+
+                        qsort(theObject->mSymbols, theObject->mSymbolCount, sizeof(SymbolStats), symbolCompare);
+                    }
+                }
+            }
+
+            /*
+            **  Loop through for output.
+            */
+            for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
+            {
+                theModule = modules + moduleLoop;
+
+                /*
+                **  Skip if there is zero drift, or no net change.
+                */
+                if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode + theModule->mSize.mData))
+                {
+                    continue;
+                }
+
+                fprintf(inOptions->mOutput, "\n");
+                fprintf(inOptions->mOutput, "%s\n", theModule->mModule);
+                fprintf(inOptions->mOutput, "\tTotal:\t%+11d (%+d/%+d)\n", theModule->mSize.mCode + theModule->mSize.mData, theModule->mSize.mCodeComposition.mPositive + theModule->mSize.mDataComposition.mPositive, theModule->mSize.mCodeComposition.mNegative + theModule->mSize.mDataComposition.mNegative);
+                fprintf(inOptions->mOutput, "\tCode:\t%+11d (%+d/%+d)\n", theModule->mSize.mCode, theModule->mSize.mCodeComposition.mPositive, theModule->mSize.mCodeComposition.mNegative);
+                fprintf(inOptions->mOutput, "\tData:\t%+11d (%+d/%+d)\n", theModule->mSize.mData, theModule->mSize.mDataComposition.mPositive, theModule->mSize.mDataComposition.mNegative);
+
+                for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
+                {
+                    theSegment = theModule->mSegments + segmentLoop;
+
+                    /*
+                    **  Skip if there is zero drift, or no net change.
+                    */
+                    if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize)
+                    {
+                        continue;
+                    }
+
+                    if(CODE == theSegment->mClass)
+                    {
+                        segmentType = "CODE";
+                    }
+                    else if(DATA == theSegment->mClass)
+                    {
+                        segmentType = "DATA";
+                    }
+
+                    fprintf(inOptions->mOutput, "\t%+11d (%+d/%+d)\t%s (%s)\n", theSegment->mSize, theSegment->mComposition.mPositive, theSegment->mComposition.mNegative, theSegment->mSegment, segmentType);
+
+                    for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
+                    {
+                        theObject = theSegment->mObjects + objectLoop;
+
+                        /*
+                        **  Skip if there is zero drift, or no net change.
+                        */
+                        if(0 == inOptions->mZeroDrift && 0 == theObject->mSize)
+                        {
+                            continue;
+                        }
+
+                        fprintf(inOptions->mOutput, "\t\t%+11d (%+d/%+d)\t%s\n", theObject->mSize, theObject->mComposition.mPositive, theObject->mComposition.mNegative, theObject->mObject);
+                        
+                        for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
+                        {
+                            theSymbol = theObject->mSymbols + symbolLoop;
+
+                            /*
+                            **  Skip if there is zero drift, or no net change.
+                            */
+                            if(0 == inOptions->mZeroDrift && 0 == theSymbol->mSize)
+                            {
+                                continue;
+                            }
+
+                            fprintf(inOptions->mOutput, "\t\t\t%+11d\t%s\n", theSymbol->mSize, theSymbol->mSymbol);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+    **  Cleanup time.
+    */
+    for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
+    {
+        theModule = modules + moduleLoop;
+        
+        for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
+        {
+            theSegment = theModule->mSegments + segmentLoop;
+            
+            for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
+            {
+                theObject = theSegment->mObjects + objectLoop;
+                
+                for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
+                {
+                    theSymbol = theObject->mSymbols + symbolLoop;
+                    
+                    CLEANUP(theSymbol->mSymbol);
+                }
+                
+                CLEANUP(theObject->mSymbols);
+                CLEANUP(theObject->mObject);
+            }
+            
+            CLEANUP(theSegment->mObjects);
+            CLEANUP(theSegment->mSegment);
+        }
+        
+        CLEANUP(theModule->mSegments);
+        CLEANUP(theModule->mModule);
+    }
+    CLEANUP(modules);
+    
+    return retval;
+}
+
+
+int initOptions(Options* outOptions, int inArgc, char** inArgv)
+/*
+**  returns int     0 if successful.
+*/
+{
+    int retval = 0;
+    int loop = 0;
+    int switchLoop = 0;
+    int match = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    Switch* current = NULL;
+
+    /*
+    **  Set any defaults.
+    */
+    memset(outOptions, 0, sizeof(Options));
+    outOptions->mProgramName = inArgv[0];
+    outOptions->mInput = stdin;
+    outOptions->mInputName = strdup("stdin");
+    outOptions->mOutput = stdout;
+    outOptions->mOutputName = strdup("stdout");
+
+    if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
+    }
+
+    /*
+    **  Go through and attempt to do the right thing.
+    */
+    for(loop = 1; loop < inArgc && 0 == retval; loop++)
+    {
+        match = 0;
+        current = NULL;
+
+        for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
+        {
+            if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+            else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+
+            if(match)
+            {
+                if(gSwitches[switchLoop]->mHasValue)
+                {
+                    /*
+                    **  Attempt to absorb next option to fullfill value.
+                    */
+                    if(loop + 1 < inArgc)
+                    {
+                        loop++;
+
+                        current = gSwitches[switchLoop];
+                        current->mValue = inArgv[loop];
+                    }
+                }
+                else
+                {
+                    current = gSwitches[switchLoop];
+                }
+
+                break;
+            }
+        }
+
+        if(0 == match)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
+        }
+        else if(NULL == current)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
+        }
+        else
+        {
+            /*
+            ** Do something based on address/swtich.
+            */
+            if(current == &gInputSwitch)
+            {
+                CLEANUP(outOptions->mInputName);
+                if(NULL != outOptions->mInput && stdin != outOptions->mInput)
+                {
+                    fclose(outOptions->mInput);
+                    outOptions->mInput = NULL;
+                }
+
+                outOptions->mInput = fopen(current->mValue, "r");
+                if(NULL == outOptions->mInput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
+                }
+                else
+                {
+                    outOptions->mInputName = strdup(current->mValue);
+                    if(NULL == outOptions->mInputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gOutputSwitch)
+            {
+                CLEANUP(outOptions->mOutputName);
+                if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
+                {
+                    fclose(outOptions->mOutput);
+                    outOptions->mOutput = NULL;
+                }
+
+                outOptions->mOutput = fopen(current->mValue, "a");
+                if(NULL == outOptions->mOutput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
+                }
+                else
+                {
+                    outOptions->mOutputName = strdup(current->mValue);
+                    if(NULL == outOptions->mOutputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gHelpSwitch)
+            {
+                outOptions->mHelp = __LINE__;
+            }
+            else if(current == &gSummarySwitch)
+            {
+                outOptions->mSummaryOnly = __LINE__;
+            }
+            else if(current == &gZeroDriftSwitch)
+            {
+                outOptions->mZeroDrift = __LINE__;
+            }
+            else if(current == &gNegationSwitch)
+            {
+                outOptions->mNegation = __LINE__;
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+void cleanOptions(Options* inOptions)
+/*
+**  Clean up any open handles.
+*/
+{
+    CLEANUP(inOptions->mInputName);
+    if(NULL != inOptions->mInput && stdin != inOptions->mInput)
+    {
+        fclose(inOptions->mInput);
+    }
+    CLEANUP(inOptions->mOutputName);
+    if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
+    {
+        fclose(inOptions->mOutput);
+    }
+
+    memset(inOptions, 0, sizeof(Options));
+}
+
+
+void showHelp(Options* inOptions)
+/*
+**  Show some simple help text on usage.
+*/
+{
+    int loop = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    const char* valueText = NULL;
+
+    printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
+    printf("\n");
+    printf("arguments:\n");
+
+    for(loop = 0; loop < switchCount; loop++)
+    {
+        if(gSwitches[loop]->mHasValue)
+        {
+            valueText = " <value>";
+        }
+        else
+        {
+            valueText = "";
+        }
+
+        printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
+        printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
+        printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
+    }
+
+    printf("This tool takes the diff of two sorted tsv files to form a summary report\n");
+    printf("of code and data size changes which is hoped to be human readable.\n");
+}
+
+
+int main(int inArgc, char** inArgv)
+{
+    int retval = 0;
+    Options options;
+
+    retval = initOptions(&options, inArgc, inArgv);
+    if(options.mHelp)
+    {
+        showHelp(&options);
+    }
+    else if(0 == retval)
+    {
+        retval = difftool(&options);
+    }
+
+    cleanOptions(&options);
+    return retval;
+}
+
diff --git a/third_party/codesighs/msdump2symdb.c b/third_party/codesighs/msdump2symdb.c
new file mode 100644
index 0000000000000..705c3c4173972
--- /dev/null
+++ b/third_party/codesighs/msdump2symdb.c
@@ -0,0 +1,1090 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is msdump2symdb.c code, released
+ * Jan 16, 2003.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Garrett Arch Blythe, 16-January-2003
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+
+#define ERROR_REPORT(num, val, msg)   fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
+#define CLEANUP(ptr)    do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
+
+
+typedef struct __struct_Options
+/*
+**  Options to control how we perform.
+**
+**  mProgramName    Used in help text.
+**  mInput          File to read for input.
+**                  Default is stdin.
+**  mInputName      Name of the file.
+**  mOutput         Output file, append.
+**                  Default is stdout.
+**  mOutputName     Name of the file.
+**  mHelp           Whether or not help should be shown.
+*/
+{
+    const char* mProgramName;
+    FILE* mInput;
+    char* mInputName;
+    FILE* mOutput;
+    char* mOutputName;
+    int mHelp;
+}
+Options;
+
+
+typedef struct __struct_Switch
+/*
+**  Command line options.
+*/
+{
+    const char* mLongName;
+    const char* mShortName;
+    int mHasValue;
+    const char* mValue;
+    const char* mDescription;
+}
+Switch;
+
+#define DESC_NEWLINE "\n\t\t"
+
+static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
+static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
+static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
+
+static Switch* gSwitches[] = {
+        &gInputSwitch,
+        &gOutputSwitch,
+        &gHelpSwitch
+};
+
+
+typedef struct __struct_MSDump_Symbol
+/*
+**  Struct to hold infomration on a symbol.
+**
+**  mSize               Size of the symbol once all work is complete.
+**  mOffset             Offset of the symbol in the section.
+**  mName               Symbolic name.
+*/
+{
+    unsigned    mSize;
+    unsigned    mOffset;
+    char*       mName;
+}
+MSDump_Symbol;
+
+
+typedef struct __struct_MSDump_Section
+/*
+**  Struct for holding information on a section.
+**
+**  mLength             Length of the section in bytes.
+**  mUsed               Number of bytes used in the section thus far.
+**                      Should eventually match mLength after work is done.
+**  mType               Type of section, as string (.data, .text, et. al.)
+**  mSymbols            Symbols found inside the section.
+**  mSymbolCount        Number of symbols in array.
+*/
+{
+    unsigned            mLength;
+    unsigned            mUsed;
+    char*               mType;
+
+    MSDump_Symbol*      mSymbols;
+    unsigned            mSymbolCount;
+}
+MSDump_Section;
+
+
+typedef struct __struct_MSDump_Object
+/*
+**  Struct for holding object's data.
+*/
+{
+    char*   mObject;
+
+    MSDump_Section*     mSections;
+    unsigned            mSectionCount;
+}
+MSDump_Object;
+
+
+typedef struct __struct_MSDump_ReadState
+/*
+**  State flags while reading the input gives us hints on what to do.
+**
+**  mSkipLines                  Number of lines to skip without parsing.
+**  mSectionDetails             Section information next, like line length.
+**  mCurrentObject              Object file we are dealing with.
+*/
+{
+    unsigned            mSkipLines;
+    unsigned            mSectionDetails;
+    MSDump_Object*      mCurrentObject;
+}
+MSDump_ReadState;
+
+
+typedef struct __struct_MSDump_Container
+/*
+**  Umbrella container for all data encountered.
+*/
+{
+    MSDump_ReadState    mReadState;
+
+    MSDump_Object*      mObjects;
+    unsigned            mObjectCount;
+}
+MSDump_Container;
+
+
+void trimWhite(char* inString)
+/*
+**  Remove any whitespace from the end of the string.
+*/
+{
+    int len = strlen(inString);
+
+    while(len)
+    {
+        len--;
+
+        if(isspace(*(inString + len)))
+        {
+            *(inString + len) = '\0';
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+
+const char* skipWhite(const char* inString)
+/*
+**  Return pointer to first non white space character.
+*/
+{
+    const char* retval = inString;
+
+    while('\0' != *retval && isspace(*retval))
+    {
+        retval++;
+    }
+
+    return retval;
+}
+
+
+const char* skipNonWhite(const char* inString)
+/*
+**  Return pointer to first white space character.
+*/
+{
+    const char* retval = inString;
+
+    while('\0' != *retval && !isspace(*retval))
+    {
+        retval++;
+    }
+
+    return retval;
+}
+
+
+void slash2bs(char* inString)
+/*
+**  Change any forward slash to a backslash.
+*/
+{
+    char* slash = inString;
+
+    while(NULL != (slash = strchr(slash, '/')))
+    {
+        *slash = '\\';
+        slash++;
+    }
+}
+
+
+const char* skipToArg(const char* inString, unsigned inArgIndex)
+/*
+**  Return pointer either to the arg or NULL.
+**  1 indexed.
+*/
+{
+    const char* retval = NULL;
+
+    while(0 != inArgIndex && '\0' != *inString)
+    {
+        inArgIndex--;
+
+        inString = skipWhite(inString);
+        if(0 != inArgIndex)
+        {
+            inString = skipNonWhite(inString);
+        }
+    }
+
+    if('\0' != *inString)
+    {
+        retval = inString;
+    }
+
+    return retval;
+}
+
+
+const char* getLastArg(const char* inString)
+/*
+**  Return pointer to last arg in string.
+*/
+{
+    const char* retval = NULL;
+    int length = 0;
+    int sawString = 0;
+
+    length = strlen(inString);
+    while(0 != length)
+    {
+        length--;
+
+        if(0 == sawString)
+        {
+            if(0 == isspace(inString[length]))
+            {
+                sawString = __LINE__;
+            }
+        }
+        else
+        {
+            if(0 != isspace(inString[length]))
+            {
+                retval = inString + length + 1;
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+int processLine(Options* inOptions, MSDump_Container* inContainer, const char* inLine)
+/*
+**  Handle one line at a time.
+**  Looking for several different types of lines.
+**  Ignore all other lines.
+**  The container is the state machine.
+**  returns 0 on no error.
+*/
+{
+    int retval = 0;
+
+    /*
+    **  Check to see if we were expecting section details.
+    */
+    if(0 != inContainer->mReadState.mSectionDetails)
+    {
+        const char* length = NULL;
+        unsigned sectionIndex = 0;
+
+        /*
+        **  Detail is a 1 based index....
+        **  Reset.
+        */
+        sectionIndex = inContainer->mReadState.mSectionDetails - 1;
+        inContainer->mReadState.mSectionDetails = 0;
+
+        if(0 == strncmp("    Section length", inLine, 18))
+        {
+            const char* sectionLength = NULL;
+            unsigned numericLength = 0;
+            char* endScan = NULL;
+
+            sectionLength = skipWhite(inLine + 18);
+
+            errno = 0;
+            numericLength = strtoul(sectionLength, &endScan, 16);
+            if(0 == errno && endScan != sectionLength)
+            {
+                inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mLength = numericLength;
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, inLine, "Cannot scan for section length.");
+            }
+        }
+        else
+        {
+            retval = __LINE__;
+            ERROR_REPORT(retval, inLine, "Cannot parse section line.");
+        }
+    }
+    /*
+    **  Check for switching object file symbols.
+    */
+    else if(0 == strncmp("Dump of file ", inLine, 13))
+    {
+        const char* dupMe = inLine + 13;
+        char* dup = NULL;
+        
+        dup = strdup(dupMe);
+        if(NULL != dup)
+        {
+            void* growth = NULL;
+            
+            trimWhite(dup);
+            slash2bs(dup);
+            
+            
+            growth = realloc(inContainer->mObjects, (inContainer->mObjectCount + 1) * sizeof(MSDump_Object));
+            if(NULL != growth)
+            {
+                unsigned int index = inContainer->mObjectCount;
+                
+                inContainer->mObjectCount++;
+                inContainer->mObjects = growth;
+                memset(inContainer->mObjects + index, 0, sizeof(MSDump_Object));
+                
+                inContainer->mObjects[index].mObject = dup;
+
+                /*
+                **  Reset the read state for this new object.
+                */
+                memset(&inContainer->mReadState, 0, sizeof(MSDump_ReadState));
+
+                /*
+                **  Record our current object file.
+                */
+                inContainer->mReadState.mCurrentObject = inContainer->mObjects + index;
+
+                /*
+                **  We can skip a few lines.
+                */
+                inContainer->mReadState.mSkipLines = 4;
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, dup, "Unable to grow object array.");
+                free(dup);
+            }
+        }
+        else
+        {
+            retval = __LINE__;
+            ERROR_REPORT(retval, dupMe, "Unable to copy string.");
+            
+        }
+    }
+    /*
+    **  Check for a symbol dump or a section header.
+    */
+    else if(isxdigit(*inLine) && isxdigit(*(inLine + 1)) && isxdigit(*(inLine + 2)))
+    {
+        const char* sectionString = NULL;
+
+        /*
+        **  Determine the section for this line.
+        **  Ignore DEBUG sections.
+        */
+        sectionString = skipToArg(inLine, 3);
+        if(NULL != sectionString)
+        {
+            if(0 != strncmp(sectionString, "DEBUG", 5) && 0 != strncmp(sectionString, "ABS", 3) && 0 != strncmp(sectionString, "UNDEF", 5))
+            {
+                /*
+                **  MUST start with "SECT"
+                */
+                if(0 == strncmp(sectionString, "SECT", 4))
+                {
+                    unsigned sectionIndex1 = 0;
+
+                    char *endScan = NULL;
+
+                    sectionString += 4;
+
+                    /*
+                    **  Convert the remaining string to an index.
+                    **  It will be 1 based.
+                    */
+                    errno = 0;
+                    sectionIndex1 = strtoul(sectionString, &endScan, 16);
+                    if(0 == errno && endScan != sectionString && 0 != sectionIndex1)
+                    {
+                        unsigned sectionIndex = sectionIndex1 - 1;
+
+                        /*
+                        **  Is this a new section? Assumed to be ascending.
+                        **  Or is this a symbol in the section?
+                        */
+                        if(sectionIndex1 > inContainer->mReadState.mCurrentObject->mSectionCount)
+                        {
+                            const char* typeArg = NULL;
+
+                            /*
+                            **  New Section, figure out the type.
+                            */
+                            typeArg = skipToArg(sectionString, 5);
+                            if(NULL != typeArg)
+                            {
+                                char* typeDup = NULL;
+
+                                /*
+                                **  Skip the leading period before duping.
+                                */
+                                if('.' == *typeArg)
+                                {
+                                    typeArg++;
+                                }
+                                typeDup = strdup(typeArg);
+
+                                if(NULL != typeDup)
+                                {
+                                    void* moved = NULL;
+                                    char* nonWhite = NULL;
+
+                                    /*
+                                    **  Terminate the duplicate after the section type.
+                                    */
+                                    nonWhite = (char*)skipNonWhite(typeDup);
+                                    if(NULL != nonWhite)
+                                    {
+                                        *nonWhite = '\0';
+                                    }
+
+                                    /*
+                                    **  Create more space for the section in the object...
+                                    */
+                                    moved = realloc(inContainer->mReadState.mCurrentObject->mSections, sizeof(MSDump_Section) * sectionIndex1);
+                                    if(NULL != moved)
+                                    {
+                                        unsigned oldCount = inContainer->mReadState.mCurrentObject->mSectionCount;
+
+                                        inContainer->mReadState.mCurrentObject->mSections = (MSDump_Section*)moved;
+                                        inContainer->mReadState.mCurrentObject->mSectionCount = sectionIndex1;
+                                        memset(&inContainer->mReadState.mCurrentObject->mSections[oldCount], 0, sizeof(MSDump_Section) * (sectionIndex1 - oldCount));
+                                        
+                                        /*
+                                        **  Other section details.
+                                        */
+                                        inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mType = typeDup;
+                                            
+                                            
+                                        /*
+                                        **  Mark it so that we look for the length on the next line.
+                                        **  This happens on next entry into the read state.
+                                        */
+                                        inContainer->mReadState.mSectionDetails = sectionIndex1;
+                                    }
+                                    else
+                                    {
+                                        retval = __LINE__;
+                                        ERROR_REPORT(retval, inLine, "Unable to grow for new section.");
+                                        free(typeDup);
+                                    }
+                                }
+                                else
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, typeArg, "Unable to duplicate type.");
+                                }
+                            }
+                            else
+                            {
+                                retval = __LINE__;
+                                ERROR_REPORT(retval, inLine, "Unable to determine section type.");
+                            }
+
+                        }
+                        else
+                        {
+                            const char* offsetArg = NULL;
+                            const char* classArg = NULL;
+                            unsigned classWords = 1;
+                            const char* symbolArg = NULL;
+
+                            /*
+                            **  This is an section we've seen before, and must list a symbol.
+                            **  Figure out the things we want to know about the symbol, e.g. size.
+                            **  We will ignore particular classes of symbols.
+                            */
+
+                            offsetArg = skipToArg(inLine, 2);
+
+                            classArg = skipToArg(offsetArg, 4);
+                            if(0 == strncmp(classArg, "()", 2))
+                            {
+                                classArg = skipToArg(classArg, 2);
+                            }
+                            if(0 == strncmp(classArg, ".bf or.ef", 9))
+                            {
+                                classWords = 2;
+                            }
+
+                            symbolArg = skipToArg(classArg, 3 + (classWords - 1));
+
+                            /*
+                            **  Skip particular lines/items.
+                            */
+                            if(
+                                0 != strncmp(classArg, "Label", 5) &&
+                                0 != strncmp(symbolArg, ".bf", 3) &&
+                                0 != strncmp(symbolArg, ".lf", 3) &&
+                                0 != strncmp(symbolArg, ".ef", 3)
+                                )
+                            {
+                                char* endOffsetArg = NULL;
+                                unsigned offset = 0;
+                                
+                                /*
+                                ** Convert the offset to something meaninful (size).
+                                */
+                                errno = 0;
+                                offset = strtoul(offsetArg, &endOffsetArg, 16);
+                                if(0 == errno && endOffsetArg != offsetArg)
+                                {
+                                    void* moved = NULL;
+                                    
+                                    /*
+                                    **  Increase the size of the symbol array in the section.
+                                    **  Assumed symbols are unique within each section.
+                                    */
+                                    moved = realloc(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols, sizeof(MSDump_Symbol) * (inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount + 1));
+                                    if(NULL != moved)
+                                    {
+                                        unsigned symIndex = 0;
+
+                                        /*
+                                        **  Record symbol details.
+                                        **  Assumed symbols are encountered in order for their section (size calc depends on it).
+                                        */
+                                        symIndex = inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount;
+                                        inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount++;
+                                        inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols = (MSDump_Symbol*)moved;
+                                        memset(&inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex], 0, sizeof(MSDump_Symbol));
+                                        
+                                        inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mOffset = offset;
+                                        
+                                        /*
+                                        **  We could allocate smarter here if it ever mattered.
+                                        */
+                                        inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName = strdup(symbolArg);
+                                        if(NULL != inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName)
+                                        {
+                                            char* trim = NULL;
+
+                                            trim = (char*)skipNonWhite(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName);
+                                            if(NULL != trim)
+                                            {
+                                                *trim = '\0';
+                                            }
+                                        }
+                                        else
+                                        {
+                                            retval = __LINE__;
+                                            ERROR_REPORT(retval, inLine, "Unable to duplicate symbol name.");
+                                        }
+                                    }
+                                    else
+                                    {
+                                        retval = __LINE__;
+                                        ERROR_REPORT(retval, inLine, "Unable to grow symbol array for section.");
+                                    }
+                                }
+                                else
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, inLine, "Unable to convert offset to a number.");
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, inLine, "Unable to determine section index.");
+                    }
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, inLine, "No match for section prefix.");
+                }
+            }
+        }
+        else
+        {
+            retval = __LINE__;
+            ERROR_REPORT(retval, inLine, "Unable to scan for section.");
+        }
+    }
+
+    return retval;
+}
+
+
+void dumpCleanup(MSDump_Container* inContainer)
+/*
+**  Attempt to be nice and free up what we have allocated.
+*/
+{
+    unsigned objectLoop = 0;
+    unsigned sectionLoop = 0;
+    unsigned symbolLoop = 0;
+
+    for(objectLoop = 0; objectLoop < inContainer->mObjectCount; objectLoop++)
+    {
+        for(sectionLoop = 0; sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
+        {
+            for(symbolLoop = 0; symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
+            {
+                CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName);
+            }
+            inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount = 0;
+            CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols);
+            CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mType);
+        }
+        inContainer->mObjects[objectLoop].mSectionCount = 0;
+        CLEANUP(inContainer->mObjects[objectLoop].mSections);
+    }
+    CLEANUP(inContainer->mObjects);
+    inContainer->mObjectCount = 0;
+}
+
+
+int qsortSymOffset(const void* in1, const void* in2)
+/*
+**  qsort callback to sort the symbols by their offset.
+*/
+{
+    MSDump_Symbol* sym1 = (MSDump_Symbol*)in1;
+    MSDump_Symbol* sym2 = (MSDump_Symbol*)in2;
+    int retval = 0;
+
+    if(sym1->mOffset < sym2->mOffset)
+    {
+        retval = 1;
+    }
+    else if(sym1->mOffset > sym2->mOffset)
+    {
+        retval = -1;
+    }
+
+    return retval;
+}
+
+
+int calcContainer(Options* inOptions, MSDump_Container* inContainer)
+/*
+**  Resposible for doing any size calculations based on the offsets known.
+**  After this calculation, each sections mUsed will match mSize.
+**  After this calculation, all symbols should know how big they are.
+*/
+{
+    int retval = 0;
+    unsigned objectLoop = 0;
+    unsigned sectionLoop = 0;
+    unsigned symbolLoop = 0;
+
+
+    /*
+    **  Need to sort all symbols by their offsets.
+    */
+    for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
+    {
+        for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
+        {
+            qsort(
+                inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols,
+                inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount,
+                sizeof(MSDump_Symbol),
+                qsortSymOffset
+                );
+        }
+    }
+
+
+    /*
+    **  Need to go through all symbols and calculate their size.
+    */
+    for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
+    {
+        for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
+        {
+            for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
+            {
+                inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize =
+                    inContainer->mObjects[objectLoop].mSections[sectionLoop].mLength -
+                    inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed -
+                    inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mOffset;
+
+                inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed += 
+                    inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize;
+            }
+        }
+    }
+
+
+    return retval;
+}
+
+
+int reportContainer(Options* inOptions, MSDump_Container* inContainer)
+/*
+**  Display all symbols and their data.
+**  We'll use a tsv format.
+*/
+{
+    int retval = 0;
+    unsigned objectLoop = 0;
+    unsigned sectionLoop = 0;
+    unsigned symbolLoop = 0;
+    int printRes = 0;
+
+    for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
+    {
+        for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
+        {
+            for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
+            {
+                printRes = fprintf(inOptions->mOutput, "%s\t%s\t%.8X\t%s\n",
+                    inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName,
+                    inContainer->mObjects[objectLoop].mSections[sectionLoop].mType,
+                    inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize,
+                    inContainer->mObjects[objectLoop].mObject
+                    );
+
+                if(0 > printRes)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, inOptions->mOutputName, "Unable to write to file.");
+                }
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+int dump2symdb(Options* inOptions)
+/*
+**  Convert the input into the output, respecting the options.
+**  Returns 0 on success.
+*/
+{
+    int retval = 0;
+    char lineBuffer[0x800];
+    MSDump_Container container;
+
+    memset(&container, 0, sizeof(container));
+
+    /*
+    **  Read the file line by line.
+    */
+    while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
+    {
+        if(0 != container.mReadState.mSkipLines)
+        {
+            container.mReadState.mSkipLines--;
+            continue;
+        }
+        retval = processLine(inOptions, &container, lineBuffer);
+    }
+
+    /*
+    **  Perform whatever calculations desired.
+    */
+    if(0 == retval)
+    {
+        retval = calcContainer(inOptions, &container);
+    }
+
+    /*
+    **  Output what we know.
+    */
+    if(0 == retval)
+    {
+        retval = reportContainer(inOptions, &container);
+    }
+
+    /*
+    **  Cleanup what we've done.
+    */
+    dumpCleanup(&container);
+
+    return retval;
+}
+
+
+int initOptions(Options* outOptions, int inArgc, char** inArgv)
+/*
+**  returns int     0 if successful.
+*/
+{
+    int retval = 0;
+    int loop = 0;
+    int switchLoop = 0;
+    int match = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    Switch* current = NULL;
+
+    /*
+    **  Set any defaults.
+    */
+    memset(outOptions, 0, sizeof(Options));
+    outOptions->mProgramName = inArgv[0];
+    outOptions->mInput = stdin;
+    outOptions->mInputName = strdup("stdin");
+    outOptions->mOutput = stdout;
+    outOptions->mOutputName = strdup("stdout");
+
+    if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
+    }
+
+    /*
+    **  Go through and attempt to do the right thing.
+    */
+    for(loop = 1; loop < inArgc && 0 == retval; loop++)
+    {
+        match = 0;
+        current = NULL;
+
+        for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
+        {
+            if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+            else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+
+            if(match)
+            {
+                if(gSwitches[switchLoop]->mHasValue)
+                {
+                    /*
+                    **  Attempt to absorb next option to fullfill value.
+                    */
+                    if(loop + 1 < inArgc)
+                    {
+                        loop++;
+
+                        current = gSwitches[switchLoop];
+                        current->mValue = inArgv[loop];
+                    }
+                }
+                else
+                {
+                    current = gSwitches[switchLoop];
+                }
+
+                break;
+            }
+        }
+
+        if(0 == match)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
+        }
+        else if(NULL == current)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
+        }
+        else
+        {
+            /*
+            ** Do something based on address/swtich.
+            */
+            if(current == &gInputSwitch)
+            {
+                CLEANUP(outOptions->mInputName);
+                if(NULL != outOptions->mInput && stdin != outOptions->mInput)
+                {
+                    fclose(outOptions->mInput);
+                    outOptions->mInput = NULL;
+                }
+
+                outOptions->mInput = fopen(current->mValue, "r");
+                if(NULL == outOptions->mInput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
+                }
+                else
+                {
+                    outOptions->mInputName = strdup(current->mValue);
+                    if(NULL == outOptions->mInputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gOutputSwitch)
+            {
+                CLEANUP(outOptions->mOutputName);
+                if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
+                {
+                    fclose(outOptions->mOutput);
+                    outOptions->mOutput = NULL;
+                }
+
+                outOptions->mOutput = fopen(current->mValue, "a");
+                if(NULL == outOptions->mOutput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
+                }
+                else
+                {
+                    outOptions->mOutputName = strdup(current->mValue);
+                    if(NULL == outOptions->mOutputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gHelpSwitch)
+            {
+                outOptions->mHelp = __LINE__;
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+void cleanOptions(Options* inOptions)
+/*
+**  Clean up any open handles.
+*/
+{
+    CLEANUP(inOptions->mInputName);
+    if(NULL != inOptions->mInput && stdin != inOptions->mInput)
+    {
+        fclose(inOptions->mInput);
+    }
+    CLEANUP(inOptions->mOutputName);
+    if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
+    {
+        fclose(inOptions->mOutput);
+    }
+
+    memset(inOptions, 0, sizeof(Options));
+}
+
+
+void showHelp(Options* inOptions)
+/*
+**  Show some simple help text on usage.
+*/
+{
+    int loop = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    const char* valueText = NULL;
+
+    printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
+    printf("\n");
+    printf("arguments:\n");
+
+    for(loop = 0; loop < switchCount; loop++)
+    {
+        if(gSwitches[loop]->mHasValue)
+        {
+            valueText = " <value>";
+        }
+        else
+        {
+            valueText = "";
+        }
+
+        printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
+        printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
+        printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
+    }
+
+    printf("This tool takes the output of \"dumpbin /symbols\" to produce a simple\n");
+    printf("tsv db file of symbols and their respective attributes, like size.\n");
+}
+
+
+int main(int inArgc, char** inArgv)
+{
+    int retval = 0;
+    Options options;
+
+    retval = initOptions(&options, inArgc, inArgv);
+    if(options.mHelp)
+    {
+        showHelp(&options);
+    }
+    else if(0 == retval)
+    {
+        retval = dump2symdb(&options);
+    }
+
+    cleanOptions(&options);
+    return retval;
+}
+
diff --git a/third_party/codesighs/msmap.h b/third_party/codesighs/msmap.h
new file mode 100644
index 0000000000000..3c528de5cffc7
--- /dev/null
+++ b/third_party/codesighs/msmap.h
@@ -0,0 +1,149 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is msmap.h code, released
+ * Oct 3, 2002.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Garrett Arch Blythe, 03-October-2002
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if !defined __msmap_H
+#define __msmap_H
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+#if 0
+}
+#endif
+
+
+/*
+**  Used to numerically represent addresses.
+*/
+typedef unsigned long address;
+
+
+typedef enum __enum_MSMap_SymbolScope
+/*
+**  Symbol scope.
+*/
+{
+    PUBLIC,
+    STATIC,
+    UNDEFINED
+}
+MSMap_SymbolScope;
+
+
+typedef enum __enum_MSMap_SegmentClass
+/*
+**  Segment class.
+*/
+{
+    CODE,
+    DATA
+}
+MSMap_SegmentClass;
+
+
+typedef struct __struct_MSMap_Segment
+/*
+**  Information about a segment.
+*/
+{
+    address mPrefix;
+    address mOffset;
+    address mLength;
+    address mUsed;
+    char* mSegment;
+    MSMap_SegmentClass mClass;
+}
+MSMap_Segment;
+
+
+typedef struct __struct_MSMap_Symbol
+/*
+**  Information about a symbol.
+*/
+{
+    address mPrefix;
+    address mOffset;
+    char* mSymbol;
+    address mRVABase;
+    char* mObject;
+    MSMap_SymbolScope mScope;
+    unsigned mSymDBSize;
+    MSMap_Segment* mSection;
+}
+MSMap_Symbol;
+
+
+typedef struct __struct_MSMap_Module
+/*
+**  Top level container of the map data.
+*/
+{
+    char* mModule;
+    time_t mTimestamp;
+    address mPreferredLoadAddress;
+    MSMap_Segment* mSegments;
+    unsigned mSegmentCount;
+    unsigned mSegmentCapacity;
+    address mEntryPrefix;
+    address mEntryOffset;
+    MSMap_Symbol* mSymbols;
+    unsigned mSymbolCount;
+    unsigned mSymbolCapacity;
+}
+MSMap_Module;
+
+
+/*
+**  How much to grow our arrays by.
+*/
+#define MSMAP_SEGMENT_GROWBY 0x10
+#define MSMAP_SYMBOL_GROWBY  0x100
+
+
+#if 0
+{
+#endif
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+
+#endif /* __msmap_H */
diff --git a/third_party/codesighs/msmap2tsv.c b/third_party/codesighs/msmap2tsv.c
new file mode 100644
index 0000000000000..91587029dccb4
--- /dev/null
+++ b/third_party/codesighs/msmap2tsv.c
@@ -0,0 +1,2237 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is msmap2tsv.c code, released
+ * Oct 3, 2002.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Garrett Arch Blythe, 03-October-2002
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "msmap.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <imagehlp.h>
+
+#define F_DEMANGLE 1
+#define DEMANGLE_STATE_NORMAL 0
+#define DEMANGLE_STATE_QDECODE 1
+#define DEMANGLE_STATE_PROLOGUE_1 2
+#define DEMANGLE_STATE_HAVE_TYPE 3
+#define DEMANGLE_STATE_DEC_LENGTH 4
+#define DEMANGLE_STATE_HEX_LENGTH 5
+#define DEMANGLE_STATE_PROLOGUE_SECONDARY 6
+#define DEMANGLE_STATE_DOLLAR_1 7
+#define DEMANGLE_STATE_DOLLAR_2 8
+#define DEMANGLE_STATE_START 9
+#define DEMANGLE_STATE_STOP 10
+#define DEMANGLE_SAFE_CHAR(eval)  (isprint(eval) ? eval : ' ')
+
+#else
+#define F_DEMANGLE 0
+#endif /* WIN32 */
+
+
+#define ERROR_REPORT(num, val, msg)   fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
+#define CLEANUP(ptr)    do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
+
+
+typedef struct __struct_SymDB_Size
+/*
+**  The size of the symbol.
+**  The size is nested withing a symbols structures to produce a fast
+**      lookup path.
+**  The objects are listed in case the client of the symdb needs to
+**      match the object name in the scenario where multiple symbol
+**      sizes are present.
+**
+**  mSize           The size of the symbol in these objects.
+**  mObjects        A list of objects containing said symbol.
+**  mObjectCount    Number of objects.
+*/
+{
+    unsigned            mSize;
+    char**              mObjects;
+    unsigned            mObjectCount;
+}
+SymDB_Size;
+
+
+typedef struct __struct_SymDB_Section
+/*
+**  Each section for a symbol has a list of sizes.
+**  Should there be exactly one size for the symbol, then that
+**      is the size that should be accepted.
+**  If there is more than one size, then a match on the object
+**      should be attempted, held withing each size.
+**
+**  mName           The section name.
+**  mSizes          The varoius sizes of the symbol in this section.
+**  mSizeCount      The number of available sizes.
+*/
+{
+    char*               mName;
+    SymDB_Size*         mSizes;
+    unsigned            mSizeCount;
+}
+SymDB_Section;
+
+
+typedef struct __struct_SymDB_Symbol
+/*
+**  Each symbol has at least one section.
+**  The section indicates what type of symbol a client may be looking for.
+**  If there is no match on the section, then the client should not trust
+**      the symbdb.
+**
+**  mName           The mangled name of the symbol.
+**  mSections       Various sections this symbol belongs to.
+**  mSectionCount   The number of sections.
+*/
+{
+    char*               mName;
+    SymDB_Section*      mSections;
+    unsigned            mSectionCount;
+}
+SymDB_Symbol;
+
+
+#define SYMDB_SYMBOL_GROWBY 0x1000 /* how many sybols to allocate at a time */
+
+
+typedef struct __struct_SymDB_Container
+/*
+**  The symbol DB container object.
+**  The goal of the symbol DB is to have exactly one SymDB_Symbol for each
+**      mangled name, no matter how ever many identical mangled names there
+**      are in the input.
+**  The input is already expected to be well sorted, futher this leads to
+**      the ability to binary search for symbol name matches.
+**
+**  mSymbols        The symbols.
+**  mSymbolCount    The number of symbols in the DB.
+**  mSymbolCapacity The number of symbols we can hold (before realloc).
+*/
+{
+    SymDB_Symbol*       mSymbols;
+    unsigned            mSymbolCount;
+    unsigned            mSymbolCapacity;
+}
+SymDB_Container;
+
+
+typedef struct __struct_Options
+/*
+**  Options to control how we perform.
+**
+**  mProgramName        Used in help text.
+**  mInput              File to read for input.
+**                      Default is stdin.
+**  mInputName          Name of the file.
+**  mOutput             Output file, append.
+**                      Default is stdout.
+**  mOutputName         Name of the file.
+**  mHelp               Whether or not help should be shown.
+**  mMatchModules       Array of strings which the module name should match.
+**  mMatchModuleCount   Number of items in array.
+**  mSymDBName          Symbol DB filename.
+**  mBatchMode          Batch mode.
+**                      When in batch mode, the input file contains a list of
+**                          map files to process.
+**                      Normally the input file is a single map file itself.
+*/
+{
+    const char* mProgramName;
+    FILE* mInput;
+    char* mInputName;
+    FILE* mOutput;
+    char* mOutputName;
+    int mHelp;
+    char** mMatchModules;
+    unsigned mMatchModuleCount;
+    char* mSymDBName;
+    SymDB_Container* mSymDB;
+    int mBatchMode;
+}
+Options;
+
+
+typedef struct __struct_Switch
+/*
+**  Command line options.
+*/
+{
+    const char* mLongName;
+    const char* mShortName;
+    int mHasValue;
+    const char* mValue;
+    const char* mDescription;
+}
+Switch;
+
+#define DESC_NEWLINE "\n\t\t"
+
+static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
+static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
+static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
+static Switch gMatchModuleSwitch = {"--match-module", "-mm", 1, NULL, "Specify a valid module name." DESC_NEWLINE "Multiple specifications allowed." DESC_NEWLINE "If a module name does not match one of the names specified then no output will occur."};
+static Switch gSymDBSwitch = {"--symdb", "-sdb", 1, NULL, "Specify a symbol tsv db input file." DESC_NEWLINE "Such a symdb is produced using the tool msdump2symdb." DESC_NEWLINE "This allows better symbol size approximations." DESC_NEWLINE "The symdb file must be pre-sorted."};
+static Switch gBatchModeSwitch = {"--batch", "-b", 0, NULL, "Runs in batch mode." DESC_NEWLINE "The input file contains a list of map files." DESC_NEWLINE "Normally the input file is a map file itself." DESC_NEWLINE "This eliminates reprocessing the symdb for multiple map files."};
+
+static Switch* gSwitches[] = {
+        &gInputSwitch,
+        &gOutputSwitch,
+        &gMatchModuleSwitch,
+        &gSymDBSwitch,
+        &gBatchModeSwitch,
+        &gHelpSwitch
+};
+
+
+typedef struct __struct_MSMap_ReadState
+/*
+**  Keep track of what state we are while reading input.
+**  This gives the input context in which we absorb the datum.
+*/
+{
+    int mHasModule;
+
+    int mHasTimestamp;
+
+    int mHasPreferredLoadAddress;
+
+    int mHasSegmentData;
+    int mSegmentDataSkippedLine;
+
+    int mHasPublicSymbolData;
+    int mHasPublicSymbolDataSkippedLines;
+
+    int mHasEntryPoint;
+
+    int mFoundStaticSymbols;
+}
+MSMap_ReadState;
+
+
+char* skipWhite(char* inScan)
+/*
+**  Skip whitespace.
+*/
+{
+    char* retval = inScan;
+
+    while(isspace(*retval))
+    {
+        retval++;
+    }
+
+    return retval;
+}
+
+void trimWhite(char* inString)
+/*
+**  Remove any whitespace from the end of the string.
+*/
+{
+    int len = strlen(inString);
+
+    while(len)
+    {
+        len--;
+
+        if(isspace(*(inString + len)))
+        {
+            *(inString + len) = '\0';
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+
+char* lastWord(char* inString)
+/*
+**  Finds and returns the last word in a string.
+**  It is assumed no whitespace is at the end of the string.
+*/
+{
+    int mod = 0;
+    int len = strlen(inString);
+
+    while(len)
+    {
+        len--;
+        if(isspace(*(inString + len)))
+        {
+            mod = 1;
+            break;
+        }
+    }
+
+    return inString + len + mod;
+}
+
+
+MSMap_Segment* getSymbolSection(MSMap_Module* inModule, MSMap_Symbol* inoutSymbol)
+/*
+**  Perform a lookup for the section of the symbol.
+**  The function could cache the value.
+*/
+{
+    MSMap_Segment* retval = NULL;
+
+    if(NULL != inoutSymbol->mSection)
+    {
+        /*
+        **  Use cached value.
+        */
+        retval = inoutSymbol->mSection;
+    }
+    else
+    {
+        unsigned secLoop = 0;
+
+        /*
+        **  Go through sections in module to find the match for the symbol.
+        */
+        for(secLoop = 0; secLoop < inModule->mSegmentCount; secLoop++)
+        {
+            if(inoutSymbol->mPrefix == inModule->mSegments[secLoop].mPrefix)
+            {
+                if(inoutSymbol->mOffset >= inModule->mSegments[secLoop].mOffset)
+                {
+                    if(inoutSymbol->mOffset < (inModule->mSegments[secLoop].mOffset + inModule->mSegments[secLoop].mLength))
+                    {
+                        /*
+                        **  We have the section.
+                        */
+                        retval = &inModule->mSegments[secLoop];
+                        break;
+                    }
+                }
+            }
+        }
+
+        /*
+        **  Cache the value for next time.
+        */
+        inoutSymbol->mSection = retval;
+    }
+
+    return retval;
+}
+
+
+int readSymDB(const char* inDBName, SymDB_Container** outDB)
+/*
+**  Intialize the symbol DB.
+**  Only call if the symbol DB should be initialized.
+*/
+{
+    int retval = 0;
+
+    /*
+    **  Initialize out arguments.
+    */
+    if(NULL != outDB)
+    {
+        *outDB = NULL;
+    }
+
+    if(NULL != outDB && NULL != inDBName)
+    {
+        FILE* symDB = NULL;
+
+        symDB = fopen(inDBName, "r");
+        if(NULL != symDB)
+        {
+            *outDB = (SymDB_Container*)calloc(1, sizeof(SymDB_Container));
+            if(NULL != *outDB)
+            {
+                char lineBuf[0x400];
+                char* symbol = NULL;
+                char* section = NULL;
+                char* object = NULL;
+                char* length = NULL;
+                unsigned lengthNum = 0;
+                char* endLength = NULL;
+                
+                /*
+                **  Read the file line by line.
+                */
+                while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), symDB))
+                {
+                    trimWhite(lineBuf);
+                    
+                    /*
+                    **  Each line has four arguments.  tab separated values (tsv).
+                    **      Symbol
+                    **      Section
+                    **      Length
+                    **      Object
+                    */
+                    
+                    symbol = skipWhite(lineBuf);
+                    if(NULL == symbol)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
+                        break;
+                    }
+                    
+                    section = strchr(symbol, '\t');
+                    if(NULL == section)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
+                        break;
+                    }
+                    *section = '\0';
+                    section++;
+                    
+                    length = strchr(section, '\t');
+                    if(NULL == length)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
+                        break;
+                    }
+                    *length = '\0';
+                    length++;
+                    
+                    object = strchr(length, '\t');
+                    if(NULL == object)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
+                        break;
+                    }
+                    *object = '\0';
+                    object++;
+                    
+                    /*
+                    **  Convert the length into a number.
+                    */
+                    errno = 0;
+                    lengthNum = strtoul(length, &endLength, 16);
+                    if(0 == errno && endLength != length)
+                    {
+                        SymDB_Symbol* dbSymbol = NULL;
+                        SymDB_Section* dbSection = NULL;
+                        SymDB_Size* dbSize = NULL;
+                        char* dbObject = NULL;
+                        void* moved = NULL;
+                        
+                        /*
+                        **  Are we looking at the same symbol as last line?
+                        **  This assumes the symdb is pre sorted!!!
+                        */
+                        if(0 != (*outDB)->mSymbolCount)
+                        {
+                            unsigned index = (*outDB)->mSymbolCount - 1;
+                            
+                            if(0 == strcmp((*outDB)->mSymbols[index].mName, symbol))
+                            {
+                                dbSymbol = &(*outDB)->mSymbols[index];
+                            }
+                        }
+                        
+                        /*
+                        **  May need to create symbol.
+                        */
+                        if(NULL == dbSymbol)
+                        {
+                            /*
+                            **  Could be time to grow the symbol pool.
+                            */
+                            if((*outDB)->mSymbolCount >= (*outDB)->mSymbolCapacity)
+                            {
+                                moved = realloc((*outDB)->mSymbols, sizeof(SymDB_Symbol) * ((*outDB)->mSymbolCapacity + SYMDB_SYMBOL_GROWBY));
+                                if(NULL != moved)
+                                {
+                                    (*outDB)->mSymbols = (SymDB_Symbol*)moved;
+                                    memset(&(*outDB)->mSymbols[(*outDB)->mSymbolCapacity], 0, sizeof(SymDB_Symbol) * SYMDB_SYMBOL_GROWBY);
+                                    (*outDB)->mSymbolCapacity += SYMDB_SYMBOL_GROWBY;
+                                }
+                                else
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, inDBName, "Unable to grow symbol DB symbol array.");
+                                    break;
+                                }
+                            }
+
+                            if((*outDB)->mSymbolCount < (*outDB)->mSymbolCapacity)
+                            {
+                                dbSymbol = &(*outDB)->mSymbols[(*outDB)->mSymbolCount];
+                                (*outDB)->mSymbolCount++;
+                                
+                                dbSymbol->mName = strdup(symbol);
+                                if(NULL == dbSymbol->mName)
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, symbol, "Unable to duplicate string.");
+                                    break;
+                                }
+                            }
+                            else
+                            {
+                                retval = __LINE__;
+                                ERROR_REPORT(retval, symbol, "Unable to grow symbol DB for symbol.");
+                                break;
+                            }
+                        }
+                        
+                        /*
+                        **  Assume we have the symbol.
+                        **
+                        **  Is this the same section as the last section in the symbol?
+                        **  This assumes the symdb was presorted!!!!
+                        */
+                        if(0 != dbSymbol->mSectionCount)
+                        {
+                            unsigned index = dbSymbol->mSectionCount - 1;
+                            
+                            if(0 == strcmp(dbSymbol->mSections[index].mName, section))
+                            {
+                                dbSection = &dbSymbol->mSections[index];
+                            }
+                        }
+                        
+                        /*
+                        **  May need to create the section.
+                        */
+                        if(NULL == dbSection)
+                        {
+                            moved = realloc(dbSymbol->mSections, sizeof(SymDB_Section) * (dbSymbol->mSectionCount + 1));
+                            if(NULL != moved)
+                            {
+                                dbSymbol->mSections = (SymDB_Section*)moved;
+                                dbSection = &dbSymbol->mSections[dbSymbol->mSectionCount];
+                                dbSymbol->mSectionCount++;
+                                
+                                memset(dbSection, 0, sizeof(SymDB_Section));
+                                
+                                dbSection->mName = strdup(section);
+                                if(NULL == dbSection->mName)
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, section, "Unable to duplicate string.");
+                                    break;
+                                }
+                            }
+                            else
+                            {
+                                retval = __LINE__;
+                                ERROR_REPORT(retval, section, "Unable to grow symbol sections for symbol DB.");
+                                break;
+                            }
+                        }
+                        
+                        /*
+                        **  Assume we have the section.
+                        **
+                        **  Is this the same size as the last size?
+                        **  This assumes the symdb was presorted!!!
+                        */
+                        if(0 != dbSection->mSizeCount)
+                        {
+                            unsigned index = dbSection->mSizeCount - 1;
+                            
+                            if(dbSection->mSizes[index].mSize == lengthNum)
+                            {
+                                dbSize = &dbSection->mSizes[index];
+                            }
+                        }
+                        
+                        /*
+                        **  May need to create the size in question.
+                        */
+                        if(NULL == dbSize)
+                        {
+                            moved = realloc(dbSection->mSizes, sizeof(SymDB_Size) * (dbSection->mSizeCount + 1));
+                            if(NULL != moved)
+                            {
+                                dbSection->mSizes = (SymDB_Size*)moved;
+                                dbSize = &dbSection->mSizes[dbSection->mSizeCount];
+                                dbSection->mSizeCount++;
+                                
+                                memset(dbSize, 0, sizeof(SymDB_Size));
+                                
+                                dbSize->mSize = lengthNum;
+                            }
+                            else
+                            {
+                                retval = __LINE__;
+                                ERROR_REPORT(retval, length, "Unable to grow symbol section sizes for symbol DB.");
+                                break;
+                            }
+                        }
+                        
+                        /*
+                        **  Assume we have the size.
+                        **
+                        **  We assume a one to one correllation between size and object.
+                        **  Always try to add the new object name.
+                        **  As the symdb is assumed to be sorted, the object names should also be in order.
+                        */
+                        moved = realloc(dbSize->mObjects, sizeof(char*) * (dbSize->mObjectCount + 1));
+                        if(NULL != moved)
+                        {
+                            dbObject = strdup(object);
+                            
+                            dbSize->mObjects = (char**)moved;
+                            dbSize->mObjects[dbSize->mObjectCount] = dbObject;
+                            dbSize->mObjectCount++;
+                            
+                            if(NULL == dbObject)
+                            {
+                                retval = __LINE__;
+                                ERROR_REPORT(retval, object, "Unable to duplicate string.");
+                                break;
+                            }
+                        }
+                        else
+                        {
+                            retval = __LINE__;
+                            ERROR_REPORT(retval, object, "Unable to grow symbol section size objects for symbol DB.");
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, length, "Unable to convert symbol DB length into a number.");
+                        break;
+                    }
+                }
+            
+                if(0 == retval && 0 != ferror(symDB))
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, inDBName, "Unable to read file.");
+                }
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, inDBName, "Unable to allocate symbol DB.");
+            }
+
+            fclose(symDB);
+            symDB = NULL;
+        }
+        else
+        {
+            retval = __LINE__;
+            ERROR_REPORT(retval, inDBName, "Unable to open symbol DB.");
+        }
+    }
+    else
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, "(NULL)", "Invalid arguments.");
+    }
+
+    return retval;
+}
+
+
+void cleanSymDB(SymDB_Container** inDB)
+/*
+**  Free it all up.
+*/
+{
+    if(NULL != inDB && NULL != *inDB)
+    {
+        unsigned symLoop = 0;
+        unsigned secLoop = 0;
+        unsigned sizLoop = 0;
+        unsigned objLoop = 0;
+
+        for(symLoop = 0; symLoop < (*inDB)->mSymbolCount; symLoop++)
+        {
+            for(secLoop = 0; secLoop < (*inDB)->mSymbols[symLoop].mSectionCount; secLoop++)
+            {
+                for(sizLoop = 0; sizLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizeCount; sizLoop++)
+                {
+                    for(objLoop = 0; objLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjectCount; objLoop++)
+                    {
+                        CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects[objLoop]);
+                    }
+                    CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects);
+                }
+                CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mName);
+                CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes);
+            }
+            CLEANUP((*inDB)->mSymbols[symLoop].mName);
+            CLEANUP((*inDB)->mSymbols[symLoop].mSections);
+        }
+        CLEANUP((*inDB)->mSymbols);
+        CLEANUP(*inDB);
+    }
+}
+
+
+int symDBLookup(const void* inKey, const void* inItem)
+/*
+**  bsearch utility routine to find the symbol in the symdb.
+*/
+{
+    int retval = 0;
+    const char* key = (const char*)inKey;
+    const SymDB_Symbol* symbol = (const SymDB_Symbol*)inItem;
+
+    retval = strcmp(key, symbol->mName);
+
+    return retval;
+}
+
+
+int fillSymbolSizeFromDB(Options* inOptions, MSMap_Module* inModule, MSMap_Symbol* inoutSymbol, const char* inMangledName)
+/*
+**  If we have a symbol DB, attempt to determine the real size of the symbol
+**      up front.
+**  This helps us later in the game to avoid performing size guesses by
+**      offset.
+*/
+{
+    int retval = 0;
+
+    /*
+    **  May need to initialize symdb.
+    */
+    if(NULL == inOptions->mSymDB && NULL != inOptions->mSymDBName)
+    {
+        retval = readSymDB(inOptions->mSymDBName, &inOptions->mSymDB);
+    }
+
+    /*
+    **  Optional
+    */
+    if(0 == retval && NULL != inOptions->mSymDB)
+    {
+        void* match = NULL;
+
+        /*
+        **  Find the symbol.
+        */
+        match = bsearch(inMangledName, inOptions->mSymDB->mSymbols, inOptions->mSymDB->mSymbolCount, sizeof(SymDB_Symbol), symDBLookup);
+        if(NULL != match)
+        {
+            SymDB_Symbol* symbol = (SymDB_Symbol*)match;
+            unsigned symDBSize = 0;
+            MSMap_Segment* mapSection = NULL;
+
+            /*
+            **  We found the symbol.
+            **
+            **  See if it has the section in question.
+            */
+            mapSection = getSymbolSection(inModule, inoutSymbol);
+            if(NULL != mapSection)
+            {
+                unsigned secLoop = 0;
+
+                for(secLoop = 0; secLoop < symbol->mSectionCount; secLoop++)
+                {
+                    if(0 == strcmp(mapSection->mSegment, symbol->mSections[secLoop].mName))
+                    {
+                        SymDB_Section* section = &symbol->mSections[secLoop];
+
+                        /*
+                        **  We have a section match.
+                        **  Should there be a single size for the symbol,
+                        **      then we just default to that.
+                        **  If more than one size, we have to do an
+                        **      object match search.
+                        **  Should there be no object match, we do nothign.
+                        */
+                        if(1 == section->mSizeCount)
+                        {
+                            symDBSize = section->mSizes[0].mSize;
+                        }
+                        else
+                        {
+                            char* mapObject = NULL;
+                            
+                            /*
+                            **  Figure out the map object file name.
+                            **  Skip any colon.
+                            **  If it doesn't have a .obj in it, not worth continuing.
+                            */
+                            mapObject = strrchr(inoutSymbol->mObject, ':');
+                            if(NULL == mapObject)
+                            {
+                                mapObject = inoutSymbol->mObject;
+                            }
+                            else
+                            {
+                                mapObject++; /* colon */
+                            }
+
+                            if(NULL != strstr(mapObject, ".obj"))
+                            {
+                                unsigned sizLoop = 0;
+                                unsigned objLoop = 0;
+                                SymDB_Size* size = NULL;
+
+                                for(sizLoop = 0; sizLoop < section->mSizeCount; sizLoop++)
+                                {
+                                    size = &section->mSizes[sizLoop];
+                                    
+                                    for(objLoop = 0; objLoop < size->mObjectCount; objLoop++)
+                                    {
+                                        if(NULL != strstr(size->mObjects[objLoop], mapObject))
+                                        {
+                                            /*
+                                            **  As we matched the object, in a particular section,
+                                            **      we'll go with this as the number.
+                                            */
+                                            symDBSize = size->mSize;
+                                            break;
+                                        }
+                                    }
+                                    
+                                    /*
+                                    **  If the object loop broke early, we break too.
+                                    */
+                                    if(objLoop < size->mObjectCount)
+                                    {
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+
+                        break;
+                    }
+                }
+            }
+
+            /*
+            **  Put the size in.
+            */
+            inoutSymbol->mSymDBSize = symDBSize;
+        }
+    }
+
+    return retval;
+}
+
+
+char* symdup(const char* inSymbol)
+/*
+**  Attempts to demangle the symbol if appropriate.
+**  Otherwise acts like strdup.
+*/
+{
+    char* retval = NULL;
+
+#if F_DEMANGLE
+    {
+        int isImport = 0;
+
+        if(0 == strncmp("__imp_", inSymbol, 6))
+        {
+            isImport = __LINE__;
+            inSymbol += 6;
+        }
+
+        if('?' == inSymbol[0])
+        {
+            char demangleBuf[0x200];
+            DWORD demangleRes = 0;
+            
+            demangleRes = UnDecorateSymbolName(inSymbol, demangleBuf, sizeof(demangleBuf), UNDNAME_COMPLETE);
+            if(0 != demangleRes)
+            {
+                if (strcmp(demangleBuf, "`string'") == 0)
+                {
+                    
+                    /* attempt manual demangling of string prefix.. */
+
+                    /* first make sure we have enough space for the
+                       updated string - the demangled string will
+                       always be shorter than strlen(inSymbol) and the
+                       prologue will always be longer than the
+                       "string: " that we tack on the front of the string
+                    */
+                    char *curresult = retval = malloc(strlen(inSymbol) + 11);
+                    const char *curchar = inSymbol;
+                    
+                    int state = DEMANGLE_STATE_START;
+
+                    /* the hex state is for stuff like ?$EA which
+                       really means hex value 0x40 */
+                    char hex_state = 0;
+                    char string_is_unicode = 0;
+
+                    /* sometimes we get a null-termination before the
+                       final @ sign - in that case, remember that
+                       we've seen the whole string */
+                    int have_null_char = 0;
+
+                    /* stick our user-readable prefix on */
+                    strcpy(curresult, "string: \"");
+                    curresult += 9;
+                    
+                    while (*curchar) {
+                        
+                        // process current state
+                        switch (state) {
+
+                            /* the Prologue states are divided up so
+                               that someday we can try to decode
+                               the random letters in between the '@'
+                               signs. Also, some strings only have 2
+                               prologue '@' signs, so we have to
+                               figure out how to distinguish between
+                               them at some point. */
+                        case DEMANGLE_STATE_START:
+                            if (*curchar == '@')
+                                state = DEMANGLE_STATE_PROLOGUE_1;
+                            /* ignore all other states */
+                            break;
+
+                        case DEMANGLE_STATE_PROLOGUE_1:
+                            switch (*curchar) {
+                            case '0':
+                                string_is_unicode=0;
+                                state = DEMANGLE_STATE_HAVE_TYPE;
+                                break;
+                            case '1':
+                                string_is_unicode=1;
+                                state = DEMANGLE_STATE_HAVE_TYPE;
+                                break;
+
+                                /* ignore all other characters */
+                            }
+                            break;
+
+                        case DEMANGLE_STATE_HAVE_TYPE:
+                            if (*curchar >= '0' && *curchar <= '9') {
+                                state = DEMANGLE_STATE_DEC_LENGTH;
+                            } else if (*curchar >= 'A' && *curchar <= 'Z') {
+                                state = DEMANGLE_STATE_HEX_LENGTH;
+                            }
+                        case DEMANGLE_STATE_DEC_LENGTH:
+                            /* decimal lengths don't have the 2nd
+                               field
+                            */
+                            if (*curchar == '@')
+                                state = DEMANGLE_STATE_NORMAL;
+                            break;
+                            
+                        case DEMANGLE_STATE_HEX_LENGTH:
+                            /* hex lengths have a 2nd field
+                               (though I have no idea what it is for)
+                            */
+                            if (*curchar == '@')
+                                state = DEMANGLE_STATE_PROLOGUE_SECONDARY;
+                            break;
+
+                        case DEMANGLE_STATE_PROLOGUE_SECONDARY:
+                            if (*curchar == '@')
+                                state = DEMANGLE_STATE_NORMAL;
+                            break;
+                        
+                        case DEMANGLE_STATE_NORMAL:
+                            switch (*curchar) {
+                            case '?':
+                                state = DEMANGLE_STATE_QDECODE;
+                                break;
+                            case '@':
+                                state = DEMANGLE_STATE_STOP;
+                                break;
+                            default:
+                                *curresult++ = DEMANGLE_SAFE_CHAR(*curchar);
+                                state = DEMANGLE_STATE_NORMAL;
+                                break;
+                            }
+                            break;
+
+                            /* found a '?' */
+                        case DEMANGLE_STATE_QDECODE:
+                            state = DEMANGLE_STATE_NORMAL;
+
+                            /* there are certain shortcuts, like
+                               "?3" means ":"
+                            */
+                            switch (*curchar) {
+                            case '1':
+                                *curresult++ = '/';
+                                break;
+                            case '2':
+                                *curresult++ = '\\';
+                                break;
+                            case '3':
+                                *curresult++ = ':';
+                                break;
+                            case '4':
+                                *curresult++ = '.';
+                                break;
+                            case '5':
+                                *curresult++ = ' ';
+                                break;
+                            case '6':
+                                *curresult++ = '\\';
+                                *curresult++ = 'n';
+                                break;
+                            case '8':
+                                *curresult++ = '\'';
+                                break;
+                            case '9':
+                                *curresult++ = '-';
+                                break;
+
+                                /* any other arbitrary ASCII value can
+                                   be stored by prefixing it with ?$
+                                */
+                            case '$':
+                                state = DEMANGLE_STATE_DOLLAR_1;
+                            }
+                            break;
+                            
+                        case DEMANGLE_STATE_DOLLAR_1:
+                            /* first digit of ?$ notation. All digits
+                               are hex, represented starting with the
+                               capital leter 'A' such that 'A' means 0x0,
+                               'B' means 0x1, 'K' means 0xA
+                            */
+                            hex_state = (*curchar - 'A') * 0x10;
+                            state = DEMANGLE_STATE_DOLLAR_2;
+                            break;
+
+                        case DEMANGLE_STATE_DOLLAR_2:
+                            /* same mechanism as above */
+                            hex_state += (*curchar - 'A');
+                            if (hex_state) {
+                                *curresult++ = DEMANGLE_SAFE_CHAR(hex_state);
+                                have_null_char = 0;
+                            }
+                            else {
+                                have_null_char = 1;
+                            }
+                            
+                            state = DEMANGLE_STATE_NORMAL;
+                            break;
+
+                        case DEMANGLE_STATE_STOP:
+                            break;
+                        }
+
+                        curchar++;
+                    }
+                    
+                    /* add the appropriate termination depending
+                       if we completed the string or not */
+                    if (!have_null_char)
+                        strcpy(curresult, "...\"");
+                    else
+                        strcpy(curresult, "\"");
+                } else {
+                    retval = strdup(demangleBuf);
+                }
+            }
+            else
+            {
+                /*
+                ** fall back to normal.
+                */
+                retval = strdup(inSymbol);
+            }
+        }
+        else if('_' == inSymbol[0])
+        {
+            retval = strdup(inSymbol + 1);
+        }
+        else
+        {
+            retval = strdup(inSymbol);
+        }
+
+        /*
+        **  May need to rewrite the symbol if an import.
+        */
+        if(NULL != retval && isImport)
+        {
+            const char importPrefix[] = "__declspec(dllimport) ";
+            char importBuf[0x200];
+            int printRes = 0;
+
+            printRes = _snprintf(importBuf, sizeof(importBuf), "%s%s", importPrefix, retval);
+            free(retval);
+            retval = NULL;
+
+            if(printRes > 0)
+            {
+                retval = strdup(importBuf);
+            }
+        }
+    }
+#else /* F_DEMANGLE */
+    retval = strdup(inSymbol);
+#endif  /* F_DEMANGLE */
+
+    return retval;
+}
+
+
+int readmap(Options* inOptions, MSMap_Module* inModule)
+/*
+**  Read the input line by line, adding it to the module.
+*/
+{
+    int retval = 0;
+    char lineBuffer[0x400];
+    char* current = NULL;
+    MSMap_ReadState fsm;
+    int len = 0;
+    int forceContinue = 0;
+    
+    memset(&fsm, 0, sizeof(fsm));
+    
+    /*
+    **  Read the map file line by line.
+    **  We keep a simple state machine to determine what we're looking at.
+    */
+    while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
+    {
+        if(forceContinue)
+        {
+            /*
+            **  Used to skip anticipated blank lines.
+            */
+            forceContinue--;
+            continue;
+        }
+
+        current = skipWhite(lineBuffer);
+        trimWhite(current);
+        
+        len = strlen(current);
+        
+        if(fsm.mHasModule)
+        {
+            if(fsm.mHasTimestamp)
+            {
+                if(fsm.mHasPreferredLoadAddress)
+                {
+                    if(fsm.mHasSegmentData)
+                    {
+                        if(fsm.mHasPublicSymbolData)
+                        {
+                            if(fsm.mHasEntryPoint)
+                            {
+                                if(fsm.mFoundStaticSymbols)
+                                {
+                                    /*
+                                    **  A blank line means we've reached the end of all static symbols.
+                                    */
+                                    if(len)
+                                    {
+                                       /*
+                                        **  We're adding a new symbol.
+                                        **  Make sure we have room for it.
+                                        */
+                                        if(inModule->mSymbolCapacity == inModule->mSymbolCount)
+                                        {
+                                            void* moved = NULL;
+                                            
+                                            moved = realloc(inModule->mSymbols, sizeof(MSMap_Symbol) * (inModule->mSymbolCapacity + MSMAP_SYMBOL_GROWBY));
+                                            if(NULL != moved)
+                                            {
+                                                inModule->mSymbolCapacity += MSMAP_SYMBOL_GROWBY;
+                                                inModule->mSymbols = (MSMap_Symbol*)moved;
+                                            }
+                                            else
+                                            {
+                                                retval = __LINE__;
+                                                ERROR_REPORT(retval, inModule->mModule, "Unable to grow symbols.");
+                                            }
+                                        }
+                                        
+                                        if(0 == retval && inModule->mSymbolCapacity > inModule->mSymbolCount)
+                                        {
+                                            MSMap_Symbol* theSymbol = NULL;
+                                            unsigned index = 0;
+                                            int scanRes = 0;
+                                            char symbolBuf[0x200];
+                                            
+                                            index = inModule->mSymbolCount;
+                                            inModule->mSymbolCount++;
+                                            theSymbol = (inModule->mSymbols + index);
+                                            
+                                            memset(theSymbol, 0, sizeof(MSMap_Symbol));
+                                            theSymbol->mScope = STATIC;
+                                            
+                                            scanRes = sscanf(current, "%x:%x %s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned*)&(theSymbol->mRVABase));
+                                            if(4 == scanRes)
+                                            {
+                                                theSymbol->mSymbol = symdup(symbolBuf);
+
+                                                if(0 == retval)
+                                                {
+                                                    if(NULL != theSymbol->mSymbol)
+                                                    {
+                                                        char *last = lastWord(current);
+                                                        
+                                                        theSymbol->mObject = strdup(last);
+                                                        if(NULL == theSymbol->mObject)
+                                                        {
+                                                            retval = __LINE__;
+                                                            ERROR_REPORT(retval, last, "Unable to copy object name.");
+                                                        }
+                                                    }
+                                                    else
+                                                    {
+                                                        retval = __LINE__;
+                                                        ERROR_REPORT(retval, symbolBuf, "Unable to copy symbol name.");
+                                                    }
+                                                }
+                                            }
+                                            else
+                                            {
+                                                retval = __LINE__;
+                                                ERROR_REPORT(retval, inModule->mModule, "Unable to scan static symbols.");
+                                            }
+                                        }
+                                    }
+                                    else
+                                    {
+                                        /*
+                                        **  All done.
+                                        */
+                                        break;
+                                    }
+                                }
+                                else
+                                {
+                                    /*
+                                    **  Static symbols are optional.
+                                    **  If no static symbols we're done.
+                                    **  Otherwise, set the flag such that it will work more.
+                                    */
+                                    if(0 == strcmp(current, "Static symbols"))
+                                    {
+                                        fsm.mFoundStaticSymbols = __LINE__;
+                                        forceContinue = 1;
+                                    }
+                                    else
+                                    {
+                                        /*
+                                        **  All done.
+                                        */
+                                        break;
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                int scanRes = 0;
+                                
+                                scanRes = sscanf(current, "entry point at %x:%x", (unsigned*)&(inModule->mEntryPrefix), (unsigned*)&(inModule->mEntryOffset));
+                                if(2 == scanRes)
+                                {
+                                    fsm.mHasEntryPoint = __LINE__;
+                                    forceContinue = 1;
+                                }
+                                else
+                                {
+                                    retval = __LINE__;
+                                    ERROR_REPORT(retval, current, "Unable to obtain entry point.");
+                                }
+                            }
+                        }
+                        else
+                        {
+                            /*
+                            **  Skip the N lines of public symbol data (column headers).
+                            */
+                            if(2 <= fsm.mHasPublicSymbolDataSkippedLines)
+                            {
+                                /*
+                                **  A blank line indicates end of public symbols. 
+                                */
+                                if(len)
+                                {
+                                    /*
+                                    **  We're adding a new symbol.
+                                    **  Make sure we have room for it.
+                                    */
+                                    if(inModule->mSymbolCapacity == inModule->mSymbolCount)
+                                    {
+                                        void* moved = NULL;
+                                        
+                                        moved = realloc(inModule->mSymbols, sizeof(MSMap_Symbol) * (inModule->mSymbolCapacity + MSMAP_SYMBOL_GROWBY));
+                                        if(NULL != moved)
+                                        {
+                                            inModule->mSymbolCapacity += MSMAP_SYMBOL_GROWBY;
+                                            inModule->mSymbols = (MSMap_Symbol*)moved;
+                                        }
+                                        else
+                                        {
+                                            retval = __LINE__;
+                                            ERROR_REPORT(retval, inModule->mModule, "Unable to grow symbols.");
+                                        }
+                                    }
+                                    
+                                    if(0 == retval && inModule->mSymbolCapacity > inModule->mSymbolCount)
+                                    {
+                                        MSMap_Symbol* theSymbol = NULL;
+                                        unsigned index = 0;
+                                        int scanRes = 0;
+                                        char symbolBuf[0x200];
+                                        
+                                        index = inModule->mSymbolCount;
+                                        inModule->mSymbolCount++;
+                                        theSymbol = (inModule->mSymbols + index);
+                                        
+                                        memset(theSymbol, 0, sizeof(MSMap_Symbol));
+                                        theSymbol->mScope = PUBLIC;
+                                        
+                                        scanRes = sscanf(current, "%x:%x %s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned *)&(theSymbol->mRVABase));
+                                        if(4 == scanRes)
+                                        {
+                                            theSymbol->mSymbol = symdup(symbolBuf);
+
+                                            if(NULL != theSymbol->mSymbol)
+                                            {
+                                                char *last = lastWord(current);
+                                                
+                                                theSymbol->mObject = strdup(last);
+                                                if(NULL != theSymbol->mObject)
+                                                {
+                                                    /*
+                                                    **  Finally, attempt to lookup the actual size of the symbol
+                                                    **      if there is a symbol DB available.
+                                                    */
+                                                    retval = fillSymbolSizeFromDB(inOptions, inModule, theSymbol, symbolBuf);
+                                                }
+                                                else
+                                                {
+                                                    retval = __LINE__;
+                                                    ERROR_REPORT(retval, last, "Unable to copy object name.");
+                                                }
+                                            }
+                                            else
+                                            {
+                                                retval = __LINE__;
+                                                ERROR_REPORT(retval, symbolBuf, "Unable to copy symbol name.");
+                                            }
+                                        }
+                                        else
+                                        {
+                                            retval = __LINE__;
+                                            ERROR_REPORT(retval, inModule->mModule, "Unable to scan public symbols.");
+                                        }
+                                    }
+                                }
+                                else
+                                {
+                                    fsm.mHasPublicSymbolData = __LINE__;
+                                }
+                            }
+                            else
+                            {
+                                fsm.mHasPublicSymbolDataSkippedLines++;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        /*
+                        **  Skip the first line of segment data (column headers).
+                        **  Mark that we've begun grabbing segement data.
+                        */
+                        if(fsm.mSegmentDataSkippedLine)
+                        {
+                            /*
+                            **  A blank line means end of the segment data.
+                            */
+                            if(len)
+                            {
+                                /*
+                                **  We're adding a new segment.
+                                **  Make sure we have room for it.
+                                */
+                                if(inModule->mSegmentCapacity == inModule->mSegmentCount)
+                                {
+                                    void* moved = NULL;
+                                    
+                                    moved = realloc(inModule->mSegments, sizeof(MSMap_Segment) * (inModule->mSegmentCapacity + MSMAP_SEGMENT_GROWBY));
+                                    if(NULL != moved)
+                                    {
+                                        inModule->mSegmentCapacity += MSMAP_SEGMENT_GROWBY;
+                                        inModule->mSegments = (MSMap_Segment*)moved;
+                                    }
+                                    else
+                                    {
+                                        retval = __LINE__;
+                                        ERROR_REPORT(retval, inModule->mModule, "Unable to grow segments.");
+                                    }
+                                }
+                                
+                                if(0 == retval && inModule->mSegmentCapacity > inModule->mSegmentCount)
+                                {
+                                    MSMap_Segment* theSegment = NULL;
+                                    unsigned index = 0;
+                                    char classBuf[0x10];
+                                    char nameBuf[0x20];
+                                    int scanRes = 0;
+                                    
+                                    index = inModule->mSegmentCount;
+                                    inModule->mSegmentCount++;
+                                    theSegment = (inModule->mSegments + index);
+                                    
+                                    memset(theSegment, 0, sizeof(MSMap_Segment));
+                                    
+                                    scanRes = sscanf(current, "%x:%x %xH %s %s", (unsigned*)&(theSegment->mPrefix), (unsigned*)&(theSegment->mOffset), (unsigned*)&(theSegment->mLength), nameBuf, classBuf);
+                                    if(5 == scanRes)
+                                    {
+                                        if('.' == nameBuf[0])
+                                        {
+                                            theSegment->mSegment = strdup(&nameBuf[1]);
+                                        }
+                                        else
+                                        {
+                                            theSegment->mSegment = strdup(nameBuf);
+                                        }
+
+                                        if(NULL != theSegment->mSegment)
+                                        {
+                                            if(0 == strcmp("DATA", classBuf))
+                                            {
+                                                theSegment->mClass = DATA;
+                                            }
+                                            else if(0 == strcmp("CODE", classBuf))
+                                            {
+                                                theSegment->mClass = CODE;
+                                            }
+                                            else
+                                            {
+                                                retval = __LINE__;
+                                                ERROR_REPORT(retval, classBuf, "Unrecognized segment class.");
+                                            }
+                                        }
+                                        else
+                                        {
+                                            retval = __LINE__;
+                                            ERROR_REPORT(retval, nameBuf, "Unable to copy segment name.");
+                                        }
+                                    }
+                                    else
+                                    {
+                                        retval = __LINE__;
+                                        ERROR_REPORT(retval, inModule->mModule, "Unable to scan segments.");
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                fsm.mHasSegmentData = __LINE__;
+                            }
+                        }
+                        else
+                        {
+                            fsm.mSegmentDataSkippedLine = __LINE__;
+                        }
+                    }
+                }
+                else
+                {
+                    int scanRes = 0;
+                    
+                    /*
+                    **  The PLA has a particular format.
+                    */
+                    scanRes = sscanf(current, "Preferred load address is %x", (unsigned*)&(inModule->mPreferredLoadAddress));
+                    if(1 == scanRes)
+                    {
+                        fsm.mHasPreferredLoadAddress = __LINE__;
+                        forceContinue = 1;
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current, "Unable to obtain preferred load address.");
+                    }
+                }
+            }
+            else
+            {
+                int scanRes = 0;
+                
+                /*
+                **  The timestamp has a particular format.
+                */
+                scanRes = sscanf(current, "Timestamp is %x", (unsigned*)&(inModule->mTimestamp));
+                if(1 == scanRes)
+                {
+                    fsm.mHasTimestamp = __LINE__;
+                    forceContinue = 1;
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current, "Unable to obtain timestamp.");
+                }
+            }
+        }
+        else
+        {
+            /*
+            **  The module is on a line by itself.
+            */
+            inModule->mModule = strdup(current);
+            if(NULL != inModule->mModule)
+            {
+                fsm.mHasModule = __LINE__;
+                forceContinue = 1;
+
+                if(0 != inOptions->mMatchModuleCount)
+                {
+                    unsigned matchLoop = 0;
+                    
+                    /*
+                    **  If this module name doesn't match, then bail.
+                    **  Compare in a case sensitive manner, exact match only.
+                    */
+                    for(matchLoop = 0; matchLoop < inOptions->mMatchModuleCount; matchLoop++)
+                    {
+                        if(0 == strcmp(inModule->mModule, inOptions->mMatchModules[matchLoop]))
+                        {
+                            break;
+                        }
+                    }
+                    
+                    if(matchLoop == inOptions->mMatchModuleCount)
+                    {
+                        /*
+                        **  A match did not occur, bail out of read loop.
+                        **  No error, however.
+                        */
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, current, "Unable to obtain module.");
+            }
+        }
+    }
+    
+    if(0 == retval && 0 != ferror(inOptions->mInput))
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
+    }
+    
+    return retval;
+}
+
+
+static int qsortRVABase(const void* in1, const void* in2)
+/*
+**  qsort callback to sort the symbols by their RVABase.
+*/
+{
+    MSMap_Symbol* sym1 = (MSMap_Symbol*)in1;
+    MSMap_Symbol* sym2 = (MSMap_Symbol*)in2;
+    int retval = 0;
+
+    if(sym1->mRVABase < sym2->mRVABase)
+    {
+        retval = -1;
+    }
+    else if(sym1->mRVABase > sym2->mRVABase)
+    {
+        retval = 1;
+    }
+
+    return retval;
+}
+
+
+static int tsvout(Options* inOptions, unsigned inSize, MSMap_SegmentClass inClass, MSMap_SymbolScope inScope, const char* inModule, const char* inSegment, const char* inObject, const char* inSymbol)
+/*
+**  Output a line of map information separated by tabs.
+**  Some items (const char*), if not present, will receive a default value.
+*/
+{
+    int retval = 0;
+
+    /*
+    **  No need to output on no size.
+    **  This can happen with zero sized segments,
+    **      or an imported symbol which has multiple names (one will count).
+    */
+    if(0 != inSize)
+    {
+        char objectBuf[0x100];
+        const char* symScope = NULL;
+        const char* segClass = NULL;
+        const char* undefined = "UNDEF";
+        
+        /*
+        **  Fill in unspecified values.
+        */
+        if(NULL == inObject)
+        {
+            sprintf(objectBuf, "%s:%s:%s", undefined, inModule, inSegment);
+            inObject = objectBuf;
+        }
+        if(NULL == inSymbol)
+        {
+            inSymbol = inObject;
+        }
+        
+        /*
+        **  Convert some enumerations to text.
+        */
+        switch(inClass)
+        {
+        case CODE:
+            segClass = "CODE";
+            break;
+        case DATA:
+            segClass = "DATA";
+            break;
+        default:
+            retval = __LINE__;
+            ERROR_REPORT(retval, "", "Unable to determine class for output.");
+            break;
+        }
+        
+        switch(inScope)
+        {
+        case PUBLIC:
+            symScope = "PUBLIC";
+            break;
+        case STATIC:
+            symScope = "STATIC";
+            break;
+        case UNDEFINED:
+            symScope = undefined;
+            break;
+        default:
+            retval = __LINE__;
+            ERROR_REPORT(retval, "", "Unable to determine scope for symbol.");
+            break;
+        }
+        
+        if(0 == retval)
+        {
+            int printRes = 0;
+            
+            printRes = fprintf(inOptions->mOutput,
+                "%.8X\t%s\t%s\t%s\t%s\t%s\t%s\n",
+                inSize,
+                segClass,
+                symScope,
+                inModule,
+                inSegment,
+                inObject,
+                inSymbol
+                );
+
+            if(0 > printRes)
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, inOptions->mOutputName, "Unable to output tsv data.");
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+void cleanModule(MSMap_Module* inModule)
+{
+    unsigned loop = 0;
+
+    for(loop = 0; loop < inModule->mSymbolCount; loop++)
+    {
+        CLEANUP(inModule->mSymbols[loop].mObject);
+        CLEANUP(inModule->mSymbols[loop].mSymbol);
+    }
+    CLEANUP(inModule->mSymbols);
+
+    for(loop = 0; loop < inModule->mSegmentCount; loop++)
+    {
+        CLEANUP(inModule->mSegments[loop].mSegment);
+    }
+    CLEANUP(inModule->mSegments);
+
+    CLEANUP(inModule->mModule);
+
+    memset(inModule, 0, sizeof(MSMap_Module));
+}
+
+
+int map2tsv(Options* inOptions)
+/*
+**  Read all input.
+**  Output tab separated value data.
+*/
+{
+    int retval = 0;
+    MSMap_Module module;
+
+    memset(&module, 0, sizeof(module));
+
+    /*
+    **  Read in the map file.
+    */
+    retval = readmap(inOptions, &module);
+    if(0 == retval)
+    {
+        unsigned symLoop = 0;
+        MSMap_Symbol* symbol = NULL;
+        unsigned secLoop = 0;
+        MSMap_Segment* section = NULL;
+        unsigned size = 0;
+        unsigned dbSize = 0;
+        unsigned offsetSize = 0;
+        unsigned endOffset = 0;
+
+        /*
+        **  Quick sort the symbols via RVABase.
+        */
+        qsort(module.mSymbols, module.mSymbolCount, sizeof(MSMap_Symbol), qsortRVABase);
+
+        /*
+        **  Go through all the symbols (in order by sort).
+        **  Output their sizes.
+        */
+        for(symLoop = 0; 0 == retval && symLoop < module.mSymbolCount; symLoop++)
+        {
+            symbol = &module.mSymbols[symLoop];
+            section = getSymbolSection(&module, symbol);
+            if (!section)
+                continue;
+
+            /*
+            **  Use the symbol DB size if available.
+            */
+            dbSize = symbol->mSymDBSize;
+
+            /*
+            **  Guess using offsets.
+            **  Is there a next symbol available?  If so, its start offset is the end of this symbol.
+            **  Otherwise, our section offset + length is the end of this symbol.
+            **
+            **  The trick is, the DB size can not go beyond the offset size, for sanity.
+            */
+            
+            /*
+            **  Try next symbol, but only if in same section.
+            **  If still not, use the end of the segment.
+            **  This implies we were the last symbol in the segment.
+            */
+            if((symLoop + 1) < module.mSymbolCount)
+            {
+                MSMap_Symbol* nextSymbol = NULL;
+                MSMap_Segment* nextSection = NULL;
+                
+                nextSymbol = &module.mSymbols[symLoop + 1];
+                nextSection = getSymbolSection(&module, nextSymbol);
+                
+                if(section == nextSection)
+                {
+                    endOffset = nextSymbol->mOffset;
+                }
+                else
+                {
+                    endOffset = section->mOffset + section->mLength;
+                }
+            }
+            else
+            {
+                endOffset = section->mOffset + section->mLength;
+            }
+
+            /*
+            **  Can now guess at size.
+            */
+            offsetSize = endOffset - symbol->mOffset;
+
+            /*
+            **  Now, determine which size to use.
+            **  This is really a sanity check as well.
+            */
+            size = offsetSize;
+            if(0 != dbSize)
+            {
+                if(dbSize < offsetSize)
+                {
+                    size = dbSize;
+                }
+            }
+
+            /*
+            **  Output the symbol with the size.
+            */
+            retval = tsvout(inOptions,
+                size,
+                section->mClass,
+                symbol->mScope,
+                module.mModule,
+                section->mSegment,
+                symbol->mObject,
+                symbol->mSymbol
+                );
+
+            /*
+            **  Make sure we mark this amount of space as used in the section.
+            */
+            section->mUsed += size;
+        }
+
+        /*
+        **  Go through the sections, and those whose length is longer than the
+        **      amount of space used, output dummy filler values.
+        */
+        for(secLoop = 0; 0 == retval && secLoop < module.mSegmentCount; secLoop++)
+        {
+            section = &module.mSegments[secLoop];
+
+            if(section && section->mUsed < section->mLength)
+            {
+                retval = tsvout(inOptions,
+                    section->mLength - section->mUsed,
+                    section->mClass,
+                    UNDEFINED,
+                    module.mModule,
+                    section->mSegment,
+                    NULL,
+                    NULL
+                    );
+            }
+        }
+    }
+
+    /*
+    **  Cleanup.
+    */
+    cleanModule(&module);
+
+    return retval;
+}
+
+
+int initOptions(Options* outOptions, int inArgc, char** inArgv)
+/*
+**  returns int     0 if successful.
+*/
+{
+    int retval = 0;
+    int loop = 0;
+    int switchLoop = 0;
+    int match = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    Switch* current = NULL;
+
+    /*
+    **  Set any defaults.
+    */
+    memset(outOptions, 0, sizeof(Options));
+    outOptions->mProgramName = inArgv[0];
+    outOptions->mInput = stdin;
+    outOptions->mInputName = strdup("stdin");
+    outOptions->mOutput = stdout;
+    outOptions->mOutputName = strdup("stdout");
+
+    if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
+    }
+
+    /*
+    **  Go through and attempt to do the right thing.
+    */
+    for(loop = 1; loop < inArgc && 0 == retval; loop++)
+    {
+        match = 0;
+        current = NULL;
+
+        for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
+        {
+            if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+            else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+
+            if(match)
+            {
+                if(gSwitches[switchLoop]->mHasValue)
+                {
+                    /*
+                    **  Attempt to absorb next option to fullfill value.
+                    */
+                    if(loop + 1 < inArgc)
+                    {
+                        loop++;
+
+                        current = gSwitches[switchLoop];
+                        current->mValue = inArgv[loop];
+                    }
+                }
+                else
+                {
+                    current = gSwitches[switchLoop];
+                }
+
+                break;
+            }
+        }
+
+        if(0 == match)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
+        }
+        else if(NULL == current)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
+        }
+        else
+        {
+            /*
+            ** Do something based on address/swtich.
+            */
+            if(current == &gInputSwitch)
+            {
+                CLEANUP(outOptions->mInputName);
+                if(NULL != outOptions->mInput && stdin != outOptions->mInput)
+                {
+                    fclose(outOptions->mInput);
+                    outOptions->mInput = NULL;
+                }
+
+                outOptions->mInput = fopen(current->mValue, "r");
+                if(NULL == outOptions->mInput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
+                }
+                else
+                {
+                    outOptions->mInputName = strdup(current->mValue);
+                    if(NULL == outOptions->mInputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gOutputSwitch)
+            {
+                CLEANUP(outOptions->mOutputName);
+                if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
+                {
+                    fclose(outOptions->mOutput);
+                    outOptions->mOutput = NULL;
+                }
+
+                outOptions->mOutput = fopen(current->mValue, "a");
+                if(NULL == outOptions->mOutput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
+                }
+                else
+                {
+                    outOptions->mOutputName = strdup(current->mValue);
+                    if(NULL == outOptions->mOutputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gHelpSwitch)
+            {
+                outOptions->mHelp = __LINE__;
+            }
+            else if(current == &gMatchModuleSwitch)
+            {
+                void* moved = NULL;
+
+                /*
+                **  Add the value to the list of allowed module names.
+                */
+                moved = realloc(outOptions->mMatchModules, sizeof(char*) * (outOptions->mMatchModuleCount + 1));
+                if(NULL != moved)
+                {
+                    outOptions->mMatchModules = (char**)moved;
+                    outOptions->mMatchModules[outOptions->mMatchModuleCount] = strdup(current->mValue);
+                    if(NULL != outOptions->mMatchModules[outOptions->mMatchModuleCount])
+                    {
+                        outOptions->mMatchModuleCount++;
+                    }
+                    else
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
+                    }
+                }
+                else
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to allocate space for string.");
+                }
+            }
+            else if(current == &gSymDBSwitch)
+            {
+                CLEANUP(outOptions->mSymDBName);
+                outOptions->mSymDBName = strdup(current->mValue);
+                if(NULL == outOptions->mSymDBName)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to duplicate symbol db name.");
+                }
+            }
+            else if(current == &gBatchModeSwitch)
+            {
+                outOptions->mBatchMode = __LINE__;
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+void cleanOptions(Options* inOptions)
+/*
+**  Clean up any open handles, et. al.
+*/
+{
+    CLEANUP(inOptions->mInputName);
+    if(NULL != inOptions->mInput && stdin != inOptions->mInput)
+    {
+        fclose(inOptions->mInput);
+    }
+    CLEANUP(inOptions->mOutputName);
+    if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
+    {
+        fclose(inOptions->mOutput);
+    }
+    while(0 != inOptions->mMatchModuleCount)
+    {
+        inOptions->mMatchModuleCount--;
+        CLEANUP(inOptions->mMatchModules[inOptions->mMatchModuleCount]);
+    }
+    CLEANUP(inOptions->mMatchModules);
+
+    cleanSymDB(&inOptions->mSymDB);
+
+    memset(inOptions, 0, sizeof(Options));
+}
+
+
+void showHelp(Options* inOptions)
+/*
+**  Show some simple help text on usage.
+*/
+{
+    int loop = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    const char* valueText = NULL;
+
+    printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
+    printf("\n");
+    printf("arguments:\n");
+
+    for(loop = 0; loop < switchCount; loop++)
+    {
+        if(gSwitches[loop]->mHasValue)
+        {
+            valueText = " <value>";
+        }
+        else
+        {
+            valueText = "";
+        }
+
+        printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
+        printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
+        printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
+    }
+
+    printf("This tool normalizes MS linker .map files for use by other tools.\n");
+}
+
+
+int batchMode(Options* inOptions)
+/*
+**  Batch mode means that the input file is actually a list of map files.
+**  We simply swap out our input file names while we do this.
+*/
+{
+    int retval = 0;
+    char lineBuf[0x400];
+    FILE* realInput = NULL;
+    char* realInputName = NULL;
+    FILE* mapFile = NULL;
+    int finalRes = 0;
+
+    realInput = inOptions->mInput;
+    realInputName = inOptions->mInputName;
+
+    while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), realInput))
+    {
+        trimWhite(lineBuf);
+
+        /*
+        **  Skip/allow blank lines.
+        */
+        if('\0' == lineBuf[0])
+        {
+            continue;
+        }
+
+        /*
+        **  Override what we believe to be the input for this line.
+        */
+        inOptions->mInputName = lineBuf;
+        inOptions->mInput = fopen(lineBuf, "r");
+        if(NULL != inOptions->mInput)
+        {
+            int mapRes = 0;
+
+            /*
+            **  Do it.
+            */
+            mapRes = map2tsv(inOptions);
+
+            /*
+            **  We report the first error that we encounter, but we continue.
+            **  This is batch mode after all.
+            */
+            if(0 == finalRes)
+            {
+                finalRes = mapRes;
+            }
+            
+            /*
+            **  Close the input file.
+            */
+            fclose(inOptions->mInput);
+        }
+        else
+        {
+            retval = __LINE__;
+            ERROR_REPORT(retval, lineBuf, "Unable to open map file.");
+            break;
+        }
+    }
+
+    if(0 == retval && 0 != ferror(realInput))
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, realInputName, "Unable to read file.");
+    }
+
+    /*
+    **  Restore what we've swapped.
+    */
+    inOptions->mInput = realInput;
+    inOptions->mInputName = realInputName;
+
+    /*
+    **  Report first map file error if there were no other operational
+    **      problems.
+    */
+    if(0 == retval)
+    {
+        retval = finalRes;
+    }
+
+    return retval;
+}
+
+
+int main(int inArgc, char** inArgv)
+{
+    int retval = 0;
+    Options options;
+
+    retval = initOptions(&options, inArgc, inArgv);
+    if(options.mHelp)
+    {
+        showHelp(&options);
+    }
+    else if(0 == retval)
+    {
+        if(options.mBatchMode)
+        {
+            retval = batchMode(&options);
+        }
+        else
+        {
+            retval = map2tsv(&options);
+        }
+    }
+
+    cleanOptions(&options);
+    return retval;
+}
+
diff --git a/third_party/codesighs/nm2tsv.c b/third_party/codesighs/nm2tsv.c
new file mode 100644
index 0000000000000..07b4563b07a68
--- /dev/null
+++ b/third_party/codesighs/nm2tsv.c
@@ -0,0 +1,505 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is nm2tsv.c code, released
+ * Oct 10, 2002.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Garrett Arch Blythe, 10-October-2002
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+
+#define ERROR_REPORT(num, val, msg)   fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
+#define CLEANUP(ptr)    do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
+
+
+typedef struct __struct_Options
+/*
+**  Options to control how we perform.
+**
+**  mProgramName    Used in help text.
+**  mInput          File to read for input.
+**                  Default is stdin.
+**  mInputName      Name of the file.
+**  mOutput         Output file, append.
+**                  Default is stdout.
+**  mOutputName     Name of the file.
+**  mHelp           Whether or not help should be shown.
+*/
+{
+    const char* mProgramName;
+    FILE* mInput;
+    char* mInputName;
+    FILE* mOutput;
+    char* mOutputName;
+    int mHelp;
+}
+Options;
+
+
+typedef struct __struct_Switch
+/*
+**  Command line options.
+*/
+{
+    const char* mLongName;
+    const char* mShortName;
+    int mHasValue;
+    const char* mValue;
+    const char* mDescription;
+}
+Switch;
+
+#define DESC_NEWLINE "\n\t\t"
+
+static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
+static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
+static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
+
+static Switch* gSwitches[] = {
+        &gInputSwitch,
+        &gOutputSwitch,
+        &gHelpSwitch
+};
+
+
+char* scanWhite(char* inScan)
+/*
+**  Scan for whitespace.
+*/
+{
+    char* retval = inScan;
+
+    while('\0' != *retval && 0 == isspace(*retval))
+    {
+        retval++;
+    }
+
+    return retval;
+}
+
+
+void trimWhite(char* inString)
+/*
+**  Remove any whitespace from the end of the string.
+*/
+{
+    int len = strlen(inString);
+
+    while(len)
+    {
+        len--;
+
+        if(isspace(*(inString + len)))
+        {
+            *(inString + len) = '\0';
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+
+int nm2tsv(Options* inOptions)
+/*
+**  Read all input.
+**  Output tab separated value data.
+**
+**  We expect our data to be in a particular format.
+**  nm --format=bsd --size-sort --print-file-name --demangle
+*/
+{
+    int retval = 0;
+    char lineBuffer[4096];  /* yes, the are some very large symbols */
+    char* module = NULL;
+    char* size = NULL;
+    char* type = NULL;
+    char* symbol = NULL;
+
+    /*
+    **  Read in the nm file.
+    */
+    while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
+    {
+        trimWhite(lineBuffer);
+
+        /*
+        ** Find the various pieces of information we'll be looking for.
+        */
+        size = strchr(lineBuffer, ':');
+        if(NULL != size)
+        {
+            *size = '\0';
+            size++;
+
+            module = strrchr(lineBuffer, '/');
+            if(NULL == module)
+            {
+                module = lineBuffer;
+            }
+            else
+            {
+                *module = '\0';
+                module++;
+            }
+
+            type = scanWhite(size);
+            *type = '\0';
+            type++;
+
+            symbol = type + 1;
+            *symbol = '\0';
+            symbol++;
+
+            /*
+            **  Skip certain types.
+            */
+            switch(*type)
+            {
+                case '-':
+                    continue;
+                    break;
+                default:
+                    break;
+            }
+
+            /*
+            **  Simply output the data with a little more interpretation.
+            **  First is size.
+            */
+            fprintf(inOptions->mOutput, "%s\t", size);
+
+            /*
+            **  Type, CODE or DATA
+            */
+            switch(toupper(*type))
+            {
+                case 'T': /* text (code) */
+                case 'W': /* weak symbol ??? */
+                    fprintf(inOptions->mOutput, "CODE\t");
+                    break;
+                default:
+                    fprintf(inOptions->mOutput, "DATA\t");
+                    break;
+            }
+
+            /*
+            **  Scope, PUBLIC, STATIC, or UNDEF
+            */
+            if(islower(*type))
+            {
+                fprintf(inOptions->mOutput, "STATIC\t");
+            }
+            else
+            {
+                switch(*type)
+                {
+                    case '?':
+                        fprintf(inOptions->mOutput, "UNDEF\t");
+                        break;
+                    default:
+                        fprintf(inOptions->mOutput, "PUBLIC\t");
+                        break;
+                }
+            }
+
+            /*
+            **  Module name, segment.
+            */
+            fprintf(inOptions->mOutput, "%s\t", module);
+            fprintf(inOptions->mOutput, "%c\t", toupper(*type));
+
+            /*
+            **  Origin
+            */
+            fprintf(inOptions->mOutput, "UNDEF:%s:%c\t", module, toupper(*type));
+
+            /*
+            **  Symbol is last.
+            */
+            fprintf(inOptions->mOutput, "%s\n", symbol);
+        }
+        else
+        {
+            retval = __LINE__;
+            ERROR_REPORT(retval, lineBuffer, "Malformed input line.");
+        }
+    }
+
+    if(0 == retval && 0 != ferror(inOptions->mInput))
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
+    }
+
+    return retval;
+}
+
+
+int initOptions(Options* outOptions, int inArgc, char** inArgv)
+/*
+**  returns int     0 if successful.
+*/
+{
+    int retval = 0;
+    int loop = 0;
+    int switchLoop = 0;
+    int match = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    Switch* current = NULL;
+
+    /*
+    **  Set any defaults.
+    */
+    memset(outOptions, 0, sizeof(Options));
+    outOptions->mProgramName = inArgv[0];
+    outOptions->mInput = stdin;
+    outOptions->mInputName = strdup("stdin");
+    outOptions->mOutput = stdout;
+    outOptions->mOutputName = strdup("stdout");
+
+    if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
+    {
+        retval = __LINE__;
+        ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
+    }
+
+    /*
+    **  Go through and attempt to do the right thing.
+    */
+    for(loop = 1; loop < inArgc && 0 == retval; loop++)
+    {
+        match = 0;
+        current = NULL;
+
+        for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
+        {
+            if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+            else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
+            {
+                match = __LINE__;
+            }
+
+            if(match)
+            {
+                if(gSwitches[switchLoop]->mHasValue)
+                {
+                    /*
+                    **  Attempt to absorb next option to fullfill value.
+                    */
+                    if(loop + 1 < inArgc)
+                    {
+                        loop++;
+
+                        current = gSwitches[switchLoop];
+                        current->mValue = inArgv[loop];
+                    }
+                }
+                else
+                {
+                    current = gSwitches[switchLoop];
+                }
+
+                break;
+            }
+        }
+
+        if(0 == match)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
+        }
+        else if(NULL == current)
+        {
+            outOptions->mHelp = __LINE__;
+            retval = __LINE__;
+            ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
+        }
+        else
+        {
+            /*
+            ** Do something based on address/swtich.
+            */
+            if(current == &gInputSwitch)
+            {
+                CLEANUP(outOptions->mInputName);
+                if(NULL != outOptions->mInput && stdin != outOptions->mInput)
+                {
+                    fclose(outOptions->mInput);
+                    outOptions->mInput = NULL;
+                }
+
+                outOptions->mInput = fopen(current->mValue, "r");
+                if(NULL == outOptions->mInput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
+                }
+                else
+                {
+                    outOptions->mInputName = strdup(current->mValue);
+                    if(NULL == outOptions->mInputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gOutputSwitch)
+            {
+                CLEANUP(outOptions->mOutputName);
+                if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
+                {
+                    fclose(outOptions->mOutput);
+                    outOptions->mOutput = NULL;
+                }
+
+                outOptions->mOutput = fopen(current->mValue, "a");
+                if(NULL == outOptions->mOutput)
+                {
+                    retval = __LINE__;
+                    ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
+                }
+                else
+                {
+                    outOptions->mOutputName = strdup(current->mValue);
+                    if(NULL == outOptions->mOutputName)
+                    {
+                        retval = __LINE__;
+                        ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
+                    }
+                }
+            }
+            else if(current == &gHelpSwitch)
+            {
+                outOptions->mHelp = __LINE__;
+            }
+            else
+            {
+                retval = __LINE__;
+                ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
+            }
+        }
+    }
+
+    return retval;
+}
+
+
+void cleanOptions(Options* inOptions)
+/*
+**  Clean up any open handles.
+*/
+{
+    CLEANUP(inOptions->mInputName);
+    if(NULL != inOptions->mInput && stdin != inOptions->mInput)
+    {
+        fclose(inOptions->mInput);
+    }
+    CLEANUP(inOptions->mOutputName);
+    if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
+    {
+        fclose(inOptions->mOutput);
+    }
+
+    memset(inOptions, 0, sizeof(Options));
+}
+
+
+void showHelp(Options* inOptions)
+/*
+**  Show some simple help text on usage.
+*/
+{
+    int loop = 0;
+    const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
+    const char* valueText = NULL;
+
+    printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
+    printf("\n");
+    printf("arguments:\n");
+
+    for(loop = 0; loop < switchCount; loop++)
+    {
+        if(gSwitches[loop]->mHasValue)
+        {
+            valueText = " <value>";
+        }
+        else
+        {
+            valueText = "";
+        }
+
+        printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
+        printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
+        printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
+    }
+
+    printf("This tool normalizes nm output for use by other tools.\n");
+    printf("GNU nm is assumed for symbol type determination.\n");
+    printf("i.e. Use this tool to parse the output of:\n");
+    printf("\t/usr/bin/nm --format=bsd --size-sort --print-file-name --demangle <exefile>\n");
+}
+
+
+int main(int inArgc, char** inArgv)
+{
+    int retval = 0;
+    Options options;
+
+    retval = initOptions(&options, inArgc, inArgv);
+    if(options.mHelp)
+    {
+        showHelp(&options);
+    }
+    else if(0 == retval)
+    {
+        retval = nm2tsv(&options);
+    }
+
+    cleanOptions(&options);
+    return retval;
+}
+
diff --git a/third_party/codesighs/nm_wrap_osx.pl b/third_party/codesighs/nm_wrap_osx.pl
new file mode 100755
index 0000000000000..cf1181fe0ad10
--- /dev/null
+++ b/third_party/codesighs/nm_wrap_osx.pl
@@ -0,0 +1,105 @@
+#!/usr/bin/perl -w
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is autosummary.linx.bash code, released
+# Oct 10, 2002.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Simon Fraser <sfraser@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+use strict;
+
+#
+# A wrapper for nm that produces output listing symbol size.
+#
+my($prev_addr) = 0;
+my($prev_module) = "";
+my($prev_kind) = "";
+my($prev_symbol) = "";
+
+open(NM_OUTPUT, "nm -fnol $ARGV[0] | c++filt |") or die "nm failed to run on $ARGV[0]\n";
+while (<NM_OUTPUT>)
+{
+  my($line) = $_;
+  chomp($line);
+  
+  if ($line =~ /^([^:]+):\s*([0-9a-f]{8}) (\w) (.+)$/)
+  {
+    my($module) = $1;
+    my($addr)   = $2;
+    my($kind)   = $3;
+    my($symbol) = $4;
+
+    #Skip absolute addresses, there should be only a few
+    if ('a' eq lc $kind) {
+        if ('trampoline_size' ne $symbol) {
+            warn "Encountered unknown absolutely addressed symbol '$symbol' in $module";
+        }
+        next;
+    }
+
+    # we expect the input to have been piped through c++filt to
+    # demangle symbols. For some reason, it doesn't always demangle
+    # all of them, so push still-mangled symbols back through c++filt again.
+    if ($symbol =~ /^(_[_Z].+)/)
+    {
+      # warn "Trying again to unmangle $1\n";
+      $symbol = `c++filt '$1'`;
+      chomp($symbol);
+      # warn "Unmangling again to $symbol\n";
+    }
+
+    my($prev_size) = hex($addr) - hex($prev_addr);
+    # print "Outputting line $line\n";
+
+    # always print one behind, because only now do we know its size
+    if ($prev_module ne "") {
+      printf "%s:%08x %s %s\n", $prev_module, $prev_size, $prev_kind, $prev_symbol;
+    }
+      
+    $prev_addr   = $addr;
+    $prev_module = $module;
+    $prev_kind   = $kind;
+    $prev_symbol = $symbol;
+  }
+  else
+  {
+    # warn "   Discaring line $line\n";
+  }
+}
+
+# we don't know how big the last symbol is, so always show 4.
+if ($prev_module ne "") {
+  printf "%s:%08x %s %s\n", $prev_module, 4, $prev_kind, $prev_symbol;
+}
diff --git a/third_party/codesighs/readelf_wrap.pl b/third_party/codesighs/readelf_wrap.pl
new file mode 100755
index 0000000000000..7e2b15e1c781d
--- /dev/null
+++ b/third_party/codesighs/readelf_wrap.pl
@@ -0,0 +1,192 @@
+#!/usr/bin/perl -w
+# -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; -*-
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is readelf_wrap.pl.
+#
+# The Initial Developer of the Original Code is
+# IBM Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Brian Ryner <bryner@brianryner.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+use strict;
+
+# Section fields (the full list of values is in <elf.h>)
+my $SECT_NUM  = 0;  # section index
+my $SECT_NAME = 1;  # section name
+my $SECT_TYPE = 2;  # section type
+my $SECT_ADDR = 3;  # section virtual address
+my $SECT_OFF  = 4;  # section offset in file
+my $SECT_SIZE = 5;  # size of section
+my $SECT_ES   = 6;  # section entry size
+my $SECT_FLG  = 7;  # section flags
+my $SECT_LK   = 8;  # link to another section
+my $SECT_INF  = 9;  # additional section info
+my $SECT_AL   = 10; # section alignment
+
+
+# Symbol fields (note: the full list of possible values for each field
+# is given in <elf.h>)
+
+my $SYM_NUM   = 0;     # unique index of the symbol
+my $SYM_VALUE = 1;     # value of the symbol
+my $SYM_SIZE  = 2;     # size of the symbol
+my $SYM_TYPE  = 3;     # type (NOTYPE, OBJECT, FUNC, SECTION, FILE, ...)
+my $SYM_BIND  = 4;     # binding/scope (LOCAL, GLOBAL, WEAK, ...)
+my $SYM_VIS   = 5;     # visibility (DEFAULT, INTERNAL, HIDDEN, PROTECTED)
+my $SYM_NDX   = 6;     # index of section the symbol is in
+my $SYM_NAME  = 7;     # name of the symbol
+my $SYM_FILE  = 8;     # (not part of readelf) file for symbol
+
+# Tell readelf to print out the list of sections and then the symbols
+die "Usage: $^X <binary>\n" unless ($#ARGV >= 0);
+my $readelf = $ENV{'READELF_PROG'};
+if (!$readelf) {
+    $readelf = 'readelf';
+}
+open(READELF_OUTPUT, "$readelf -Ss $ARGV[0] 2>/dev/null | c++filt |") or die "readelf failed to run on $ARGV[0]\n";
+
+my @section_list;
+my @symbol_list;
+my ($module) = ($ARGV[0] =~ /([^\/]+)$/);
+my $in_symbols = 0;
+
+while (<READELF_OUTPUT>) {
+
+    if (!$in_symbols) {
+        if (/^ *\[ *(\d+)\]/) {
+            my @section;
+
+            # note that we strip off the leading '.' of section names for
+            # readability
+            if (! (@section = (/^ *\[ *(\d+)\] \.([\w\.\-]+) *(\w+) *(.{8}) (.{6}[0-9a-fA-F]*) (.{6}[0-9a-fA-F]*) *(\d+) ([a-zA-Z]+ +| +[a-zA-Z]+|) *(\d+) *(\w+) *(\d+)/))) {
+                # capture the 'null' section which has no name, so that the
+                # array indices are the same as the section indices.
+
+                @section = ($1, '', 'NULL', '00000000', '000000', '000000',
+                            '00', '', '0', '0', '0');
+            }
+
+            push (@section_list, \@section);
+        } elsif (/^Symbol table/) {
+            $in_symbols = 1;
+        }
+    } else {
+
+        my @sym;
+
+        if (@sym = /^\s*(\d+): (\w+)\s*(\d+)\s*(\w+)\s*(\w+)\s*(\w+)\s*(\w+) (.*)/)
+        {
+            # Filter out types of symbols that we don't care about:
+            #  - anything that's not of type OBJECT or FUNC
+            #  - any undefined symbols (ndx = UND[EF])
+            #  - any 0-size symbols
+
+            if (($sym[$SYM_TYPE] !~ /^(OBJECT|FUNC)$/) ||
+                $sym[$SYM_NDX] eq 'UND' || $sym[$SYM_NDX] eq 'UNDEF'
+                || $sym[$SYM_SIZE] eq '0') {
+                next;
+            }
+            push (@symbol_list, \@sym);
+        }
+        elsif (/^Symbol table .*'\.symtab'/) {
+            # We've been using .dynsym up to this point, but if we have .symtab
+            # available, it will have everything in .dynsym and more.
+            # So, reset our symbol list.
+
+            @symbol_list = ();
+        }
+    }
+}
+
+close(READELF_OUTPUT);
+
+# spit them out in codesighs TSV format
+my $sym;
+my @section_sizes;
+$#section_sizes = $#section_list;
+foreach (@section_sizes) { $_ = 0; }
+
+foreach $sym (@symbol_list) {
+    # size
+    printf "%08x\t", $sym->[$SYM_SIZE];
+
+    # code or data
+    if ($sym->[$SYM_TYPE] eq 'FUNC') {
+        print "CODE\t";
+    } else {  # OBJECT
+        print "DATA\t";
+    }
+
+    # scope
+    if ($sym->[$SYM_BIND] eq 'LOCAL') {
+        print "STATIC\t";
+    } elsif ($sym->[$SYM_BIND] =~ /(GLOBAL|WEAK)/) {
+        print "PUBLIC\t";
+    } else {
+        print "UNDEF\t";
+    }
+
+    # module name
+
+    print "$module\t";
+
+    # section
+    my $section = $section_list[$sym->[$SYM_NDX]]->[$SECT_NAME];
+    print "$section\t";
+
+    # should be the object file, but for now just module/section
+    print "UNDEF:$module:$section\t";
+
+    # now the symbol name
+    print $sym->[$SYM_NAME]."\n";
+
+    # update our cumulative section sizes
+    $section_sizes[$section_list[$sym->[$SYM_NDX]]->[$SECT_NUM]] += $sym->[$SYM_SIZE];
+}
+
+# Output extra entries to make the sum of the symbol sizes equal the
+# section size.
+
+my $section;
+foreach $section (@section_list) {
+
+    my $diff = hex($section->[$SECT_SIZE]) - $section_sizes[$section->[$SECT_NUM]];
+    if ($diff > 0) {
+        my $sectname = $section->[$SECT_NAME];
+        if ($section->[$SECT_NAME] =~ /^(rodata|data|text|bss)/) {
+            printf "%08x", $diff;
+            print "\tDATA\tSTATIC\t$module\t$sectname\tUNDEF:$module:$sectname\t.nosyms.$sectname\n";
+#        } else {
+#            print "ignoring $diff bytes of empty space in $sectname section\n";
+        }
+    }
+}
-- 
GitLab