├── .github └── workflows │ └── build-and-test.yml ├── .gitignore ├── CHANGES ├── FEATURES ├── INSTALL ├── LICENSE ├── Makefile ├── README.MD ├── TODO ├── VERSION ├── autoexp.expand ├── autoexp.visualizer ├── src ├── LastError.h ├── NatvisFile.natvis ├── PEImage.cpp ├── PEImage.h ├── cv2pdb.cpp ├── cv2pdb.h ├── cv2pdb.sln ├── cv2pdb.vcproj ├── cv2pdb.vcxproj ├── cv2pdb.vcxproj.filters ├── cv2pdb_vs12.sln ├── cvt80to64.asm ├── cvutil.cpp ├── cvutil.h ├── dcvinfo.h ├── demangle.cpp ├── demangle.h ├── dumplines.cpp ├── dumplines.vcxproj ├── dviewhelper │ ├── dviewhelper.cpp │ ├── dviewhelper.vcproj │ ├── dviewhelper.vcxproj │ └── dviewhelper.vcxproj.filters ├── dwarf.h ├── dwarf2pdb.cpp ├── dwarflines.cpp ├── main.cpp ├── managed │ ├── cv2pdb.vcproj │ └── main.cpp ├── mscvpdb.h ├── mspdb.cpp ├── mspdb.h ├── packages.config ├── packages │ ├── Microsoft.VisualStudio.Setup.Configuration.Native.1.16.30 │ │ ├── build │ │ │ └── native │ │ │ │ └── Microsoft.VisualStudio.Setup.Configuration.Native.targets │ │ └── lib │ │ │ └── native │ │ │ └── include │ │ │ └── Setup.Configuration.h │ └── repositories.config ├── readDwarf.cpp ├── readDwarf.h ├── symutil.cpp └── symutil.h └── test ├── Makefile ├── cvtest.d ├── cvtest.vcproj ├── cvtest.vcxproj └── test.visualdproj /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: build and test cv2pdb 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | # Path to the solution file relative to the root of the project. 7 | SOLUTION_FILE_PATH: src/cv2pdb.vcxproj 8 | 9 | # Configuration type to build. 10 | BUILD_CONFIGURATION: Release 11 | BUILD_PLATFORM_TOOLSET: v142 12 | 13 | jobs: 14 | build: 15 | runs-on: windows-latest 16 | strategy: 17 | matrix: 18 | BUILD_PLATFORM: [x64, ARM64] 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Add MSBuild to PATH 22 | uses: microsoft/setup-msbuild@v2 23 | - name: Build cv2pdb 24 | working-directory: ${{env.GITHUB_WORKSPACE}} 25 | run: msbuild /m /p:PlatformToolset=${{env.BUILD_PLATFORM_TOOLSET}} /p:Platform=${{matrix.BUILD_PLATFORM}} /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} 26 | - name: Build dumplines 27 | working-directory: ${{env.GITHUB_WORKSPACE}} 28 | run: msbuild /m /p:PlatformToolset=${{env.BUILD_PLATFORM_TOOLSET}} /p:Platform=Win32 /p:Configuration=${{env.BUILD_CONFIGURATION}} src/dumplines.vcxproj 29 | - name: Upload bin/ 30 | if: matrix.BUILD_PLATFORM == 'x64' 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: bin 34 | path: bin 35 | test-with-g4w-sdk: 36 | runs-on: windows-latest 37 | needs: build 38 | steps: 39 | - name: Download bin/ 40 | uses: actions/download-artifact@v4 41 | with: 42 | name: bin 43 | path: bin 44 | - uses: git-for-windows/setup-git-for-windows-sdk@v1 45 | - name: verify using Git for Windows' GCC 46 | shell: bash 47 | run: | 48 | set -x && 49 | cat >hello.c <<-\EOF && 50 | #include 51 | 52 | int main(int argc, char **argv) 53 | { 54 | printf("Hello, world\n"); 55 | return 0; 56 | } 57 | EOF 58 | 59 | gcc -g -o hello.exe hello.c && 60 | bin/${{env.BUILD_CONFIGURATION}}*/cv2pdb.exe hello.exe world.exe && 61 | 62 | ls -l hello* world* && 63 | 64 | curl -Lo cvdump.exe https://raw.githubusercontent.com/microsoft/microsoft-pdb/HEAD/cvdump/cvdump.exe && 65 | ./cvdump.exe world.pdb >world.cvdump && 66 | grep '^S_PUB32: .*, Flags: 00000000, main$' world.cvdump 67 | - name: verify split functions 68 | shell: bash 69 | run: | 70 | set -x && 71 | cat >split.c <<-\EOF && 72 | __attribute__((cold,noinline)) void cold() { volatile int i=0; } 73 | __attribute__((dllexport)) void split_func(int i) 74 | { 75 | if (i) 76 | cold(); 77 | } 78 | EOF 79 | 80 | gcc -g -O2 -shared -o split-dwarf.dll split.c && 81 | bin/${{env.BUILD_CONFIGURATION}}*/cv2pdb.exe split-dwarf.dll split-cv.dll && 82 | 83 | ls -l split-dwarf* split-cv* && 84 | 85 | curl -Lo cvdump.exe https://raw.githubusercontent.com/microsoft/microsoft-pdb/HEAD/cvdump/cvdump.exe && 86 | ./cvdump.exe split-cv.pdb > split-cv.dump && 87 | awk '$2 == "S_GPROC32:" && $NF == "split_func" { scope=gensub(/,/,"",1,$3); } $2 == "S_SEPCODE:" { getline; if ($4 == scope) found=1; } END {exit !found; }' split-cv.dump 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /src/cv2pdb_vs12.sdf 3 | /src/cv2pdb_vs12.v12.suo 4 | /test/obj 5 | *.user 6 | /src/.vs 7 | /src/*.opensdf 8 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 2 | This is the CHANGES file for cv2pdb, a 3 | converter of DMD CodeView/DWARF debug information to PDB files 4 | 5 | Copyright (c) 2009-2012 by Rainer Schuetze, All Rights Reserved 6 | 7 | Version history 8 | --------------- 9 | 10 | 2009-05-08 Version 0.1 11 | 12 | * initial release 13 | 14 | 2009-05-16 Version 0.2 15 | 16 | * replace .debug section in executable rather than rename it. (only works 17 | if it is the last section). 18 | * support for field type LF_VFUNCTAB and symbol type S_CONSTANT used by DMC. 19 | * added stringview to autoexp.dat for full length text display. 20 | 21 | 2009-06-04 Version 0.3 22 | 23 | * static members' debug info was not correctly converted, causing debugger confusion 24 | * now works on executables compiled by DMC 25 | - added command line switch -C to disable some D feature and 26 | to remove function name from local variables 27 | - added support for type LF_BITFIELD. 28 | * added fields __viewhelper to classes string and object 29 | * new addin dviewhelper.dll to display correctly terminated strings 30 | and derived object type 31 | 32 | 2009-06-05 Version 0.4 33 | 34 | * fixed crash when long is used as index or element type of dynamic or 35 | associative arrays 36 | 37 | 2009-06-06 Version 0.5 38 | 39 | * fixed error in __viewhelper field of string type, that could screw up type info 40 | * added support for wstring and dstring 41 | * fixed problems with debug info inside library by combining debug info of different modules 42 | into a single pseudo-module 43 | * now also replaces '.' by '@' in enumerator types for more consistent debug info 44 | 45 | 2009-06-07 Version 0.6 46 | 47 | * removed LF_DERIVED info from debug info, as it is inconsistent in DMD generated info 48 | with more than 4096 type entries 49 | 50 | 2009-06-08 Version 0.7 51 | 52 | * corrected number of field entries in classes or struct, because DMD miscounts private members 53 | 54 | 2009-06-11 Version 0.8 55 | 56 | * tweaked visualizer macros to detect uninitialized associative arrays and to limit expansion 57 | to arrays with less than 1024 entries 58 | * renamed data pointer member of dynamic arrays to "ptr" to be consistent with the array property 59 | in D. 60 | 61 | 2009-06-19 Version 0.9 62 | 63 | * fixed line number info at the end of a segment or when switching to another file 64 | because of inline expansion 65 | * fixed line numbers > 32767 and sections with 0 line number entries 66 | 67 | 2009-08-12 Version 0.10 68 | 69 | * better support for DMC: 70 | - entries LF_FRIENDFCN removed 71 | - entries LF_FRIENDCLS, LF_VBCLASS and LF_IVBCLASS converted 72 | thanks to Andrew. 73 | * derived-classes info in class entry now cleared to be consistent with removal of LF_DERIVED 74 | 75 | 2009-12-29 Version 0.11 76 | 77 | * basic types now show with their D names, not as C types 78 | * "enum" prefix removed from type names of enumerator types 79 | * added type information for complex data types 80 | * dmd-patch needed for long/ulong support (http://d.puremagic.com/issues/show_bug.cgi?id=3373) 81 | * experimental hack to add lexical scope to local variables (dmd patch in 82 | http://d.puremagic.com/issues/show_bug.cgi?id=3657 needed) 83 | 84 | 2010-04-13 Version 0.12 85 | 86 | * added patch to convert binaries produced by Metroworks CodeWarrior 87 | * names of local function are now demangled 88 | * dmd 2.041 fixes long/ulong support (patch http://d.puremagic.com/issues/show_bug.cgi?id=3373 89 | no longer needed) 90 | * added managed C++ project to integrate cv2pdb with CLR (thanks to Alexander Bothe) 91 | * dmd 2.043 uses different implementation of associative arrays, use command line 92 | option -D 2.043 or above to produce the respective debug info 93 | 94 | 2010-06-03 Version 0.13 95 | 96 | * adapted to mspdb100.dll which comes with VS2010 97 | * tweaked autoexp.dat modifications to be more stable with uninitialized data 98 | * autoexp.snippet now split into two files: autoexp.expand and autoexp.visualizer 99 | 100 | 2010-06-23 Version 0.14 101 | 102 | * 64-integer types are now displayed as "dlong" and "ulong" instead of "__int64" and 103 | "unsigned __int64" 104 | * improved support for long and ulong for DMD versions before 1.057 and 2.041 105 | * DMC also emits D-types for "long long" and "unsigned long long", these are 106 | translated back to the correct types if command option -C is used 107 | * now adding properties "has nested type" and "is nested type" to class/struct/union/enum types 108 | * better support for enumerators: now added as user defined types (DMD patch needed) 109 | 110 | 2010-08-08 Version 0.15 111 | 112 | * thanks to patches by Z3N, the resulting pdb is now usable by more debuggers 113 | * now uses shared file access to executable 114 | * incomplete structs/classes are now added as user defined types to avoid confusing 115 | debugger for following symbols 116 | * fixed name demangling of very long names 117 | * added name demangling support for @safe/@trusted/@property/pure/nothrow/ref 118 | * base classes are added to D/cpp-interfaces to allow viewing the virtual function 119 | table pointer 120 | * structs, classes and interfaces now have an internal qualifier attached that allows 121 | the preview in autoexp.dat to show better info for structs and interfaces 122 | 123 | 2010-08-10 Version 0.16 124 | 125 | * fixed crash when working with -C (introduced in last version) 126 | 127 | 2010-09-04 Version 0.17 128 | 129 | * fixed crash that could occur for user-defined types longer than 90 characters 130 | 131 | 2010-10-24 Version 0.18 132 | 133 | * fixed error with nested types longer than 255 characters 134 | * more fixes for names longer than 300 characters 135 | 136 | 2010-12-10 Version 0.19 137 | 138 | * now converting only class pointers to references, not pointers to structs or void 139 | * changed default D-version to 2.043 to create correct associative array type 140 | information for recent compilers by default 141 | 142 | 2010-12-30 Version 0.20 143 | 144 | * fixed another issue with user defined type names longer than 300 characters 145 | * now corrects the debug info when dmc/optlink emits multiple struct definitions, 146 | but only one UDT record. 147 | 148 | 2010-05-08 Version 0.21 149 | 150 | * fixed decoding of compressed symbols 151 | * added command line switch -n to disable symbol demangling 152 | * fixed crash with more than 32767 types 153 | 154 | unreleased Version 0.22 155 | 156 | * added command line switch -s to specify the replacement character for '.' in symbols 157 | * fixed another crash where compressed symbols expand to more than 4096 characters 158 | 159 | 2012-02-12 Version 0.23 160 | 161 | * disabled named enumerator for D basic types to avoid debugger troubles displaying arrays 162 | * added command line switch -e to enable using named enumerator for D basic types 163 | * added DWARF support 164 | * added x64 support 165 | * tweaked visualizer for associative array element to just show key and value 166 | 167 | 2012-05-01 Version 0.24 168 | 169 | * supports unicode characters in file names 170 | * improve interpretation of DWARF location expression 171 | 172 | 2012-06-18 Version 0.25 173 | 174 | * new option -p allows to specify the embedded PDB reference in the binary 175 | * added support for VS2012 176 | 177 | 2012-11-09 Version 0.26 178 | 179 | * now iterating over multiple entries in the debug directory to find CV info 180 | 181 | 2013-05-11 Version 0.27 182 | 183 | * fixed crash when converting DWARF locations using 8 bytes or more 184 | 185 | 2013-11-16 Version 0.28 186 | 187 | * added searching mspdb120.dll for VS 2013 188 | * changed search order for mspdb*.dll: trying to load through PATH first 189 | newest VS versions preferred, then trying through installation paths for VS 2013-2005 190 | * dviewhelper.dll now avoids being reloaded for every expression 191 | 192 | 2014-02-19 Version 0.29 193 | 194 | * fix DWARF conversion for newer gcc versions (4.8.0 or even earlier) 195 | 196 | 2014-02-25 Version 0.30 197 | 198 | * fixed crash when converting DWARF for executables without .reloc segment 199 | 200 | 2014-03-01 Version 0.31 201 | 202 | * added support for local variables accessed through esp 203 | 204 | 2014-09-24 Version 0.32 205 | 206 | * DWARF: fixed relocations in .debug_line section 207 | * tweaked visualizer macros to display void[], limit array preview to 64 entries 208 | 209 | 2014-12-19 Version 0.33 210 | 211 | * DWARF: revamped location expression evaluator by Vadim Chugunov 212 | 213 | 2015-02-17 Version 0.34 214 | 215 | * DWARF: fixed issues with DW_FORM_strp, DW_AT_upper_bound and DW_AT_lower_bound 216 | * DWARF: translate __int128 to CV code 0x14, just a wild guesss 217 | 218 | * DWARF: add support for DW_ATE_UTF, remove bad assert 219 | 220 | 2015-05-08 Version 0.35 221 | 222 | * new tool dumplines to display the debug line number info 223 | 224 | 2015-06-03 Version 0.36 225 | 226 | * last version introduced a regression that could cause DWARF conversion to crash 227 | * DWARF sections now stripped from image (if last sections) 228 | * add support for VS 2015 229 | 230 | 2015-06-17 Version 0.37 231 | 232 | * DWARF: improved support for gcc 4.9.0 and clang 3.6 233 | * DWARF: support debug_frame (CFA) and debug_loc (for frame base) for better support for locals 234 | * write correct machine type for x64 to PDB 235 | 236 | 2016-08-09 Version 0.38 237 | 238 | * allow anonymous typedefs 239 | * cv2pdb now builds as x64 application 240 | * truncate symbols that are to long 241 | * better support for symbols that contain non-ascii characters: do not uncompress names in field lists 242 | * copy symbol unmodified if uncompression fails 243 | 244 | 2017-01-20 Version 0.39 245 | 246 | * do not assume sorted line numbers per segment 247 | 248 | 2017-05-13 Version 0.40 249 | 250 | * set source language 'D' in compilation unit 251 | * for D version >= 2.068, write AA debug info compatible with dmd COFF output 252 | * prefer struct over class for internal structs 253 | * handle class/struct property "uniquename" 254 | 255 | 2017-05-13 Version 0.41 256 | 257 | * when using mspdb120.dll (VS2013) or later, do not emit view helpers 258 | * remove method declarations from struct or class records (they confuse mspdb*.dll if having forward references?) 259 | 260 | 2017-09-02 Version 0.42 261 | 262 | * search VS2017 registry entries to find mspdb140.dll 263 | * when using mspdb140.dll (VS2015) or later, use symbols to emit line numbers 264 | * translate S_UDT_V1 to V3 version 265 | * translate S_BLOCK_V1 to V3 version 266 | * remove "this" from delegate parameter list if inconsistent with procedure type 267 | 268 | 2017-11-30 Version 0.43 269 | 270 | * DWARF: fix crash with AUX data in symbol table 271 | * improve reallocation strategy 272 | 273 | 2018-03-30 Version 0.44 274 | 275 | * DWARF: improvements for ADA: better enumerator types, improved lexical scope (thanks to @pmderodat) 276 | * if no debug information found in executable, now looks for epononymous DBG file 277 | to load CV from (thanks to @AlexWhiter) 278 | 279 | 2019-01-25 Version 0.45 280 | 281 | * support converting DBG file to PDB 282 | * fiexd alignment of debug section. 283 | * DWARF: add support for local variables with location list via DW_FORM_sec_offset 284 | * fixed some minor DWARF issues/crashes 285 | * detect Visual Studio through COM API 286 | * set architecture of .pdb for a 64 bit .dbg 287 | * always convert S_BPREL_V1 to S_BPREL_V3 (no longer supported by mspdb 14.16.27012/VS 15.9) 288 | * emit "elemtype[keytype]" instead of "dAssocArray" 289 | * DWARF: fixed converting unnamed structs/unions as part of other structs 290 | 291 | 2019-09-03 Version 0.46 292 | 293 | * DWARF: fix writing info for aggregates larger than 32kB 294 | 295 | 2019-11-02 Version 0.47 296 | 297 | * add support for char16_t and char32_t (emitted by dmd 2.089+ for dchar) 298 | * fix loading 64-bit mspdb140.dll in VS2019 299 | 300 | 2020-03-26 Version 0.48 301 | 302 | * DWARF: add support for data symbols imported from DLL 303 | 304 | 2021-10-30 Version 0.49 305 | 306 | * Added rudimentary support for DWARF5. Thanks to dscho. 307 | 308 | * also search mspdb* DLL via vswhere.exe. Thanks to dscho. 309 | 310 | 2021-12-13 Version 0.50 311 | 312 | * Added support for DWARF5. Thanks to neerajsi-msft. 313 | 314 | 2022-03-27 Version 0.51 315 | 316 | * fix handling of UNC paths. Thanks to sonyps5201314. 317 | * DWARF: added support for non-contiguous functions. Thanks to marc-groundctl 318 | * Fixed stalling if vswhere doesn't produce any output 319 | 320 | 2022-05-28 Version 0.52 321 | 322 | * support DW_FORM_data1 and DW_FORM_data2 in DW_LNCT_directory_index 323 | * fix emitting bad debug info if struct description exceeds 64 kB, clipped for now 324 | 325 | 2023-06-10 Version 0.53 326 | 327 | * DWARF: fully-qualified name generation for procs, structs, enums and classes. 328 | Thanks to alexbudfb 329 | 330 | -------------------------------------------------------------------------------- /FEATURES: -------------------------------------------------------------------------------- 1 | Main Features 2 | 3 | * conversion of DMD/DMC CodeView information to PDB file 4 | * converted line number info allows setting breakpoints 5 | * display of variables, fields and objects in watch, local and auto 6 | window and in data tooltips 7 | * convenient display of dynamic and associative arrays in watch windows 8 | * demangled function names for convenient display of callstack 9 | 10 | More features 11 | 12 | This list is a bit more technical and shows what is actually done to 13 | achieve the desired functionality: 14 | 15 | * replaces '.' in class names with '@' to avoid confusing debugger 16 | * converts class pointers to reference for "clss.field" syntax 17 | * converts the type of member function, so that "this" is an object 18 | pointer, allowing the debugger to display fields without "this." 19 | * generates generic debug info for dynamic arrays, associative arrays 20 | and delegates 21 | * creates readable type names for display of D specific types 22 | * autoexp.dat formats output for dynamic and associative arrays in 23 | watch windows 24 | * autoexp.dat filters display of null references 25 | * adds object class debug info 26 | * "char[]", "wchar[]" and "dchar[]" (D1) or "const char[]", 27 | "const wchar[]" and "const dchar[]" (D2) translated to "string", 28 | "wstring" and "dstring", respectively 29 | * converts type delegate to __int64 30 | * addin dviewhelper.dll allows correct display of D style strings 31 | and derived object type 32 | * maps D basic types to enumerators to overload C style names 33 | * add struct definitions for complex data types 34 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 2 | This is the INSTALL file for cv2pdb, a 3 | converter of DMD CodeView/DWARF debug information to PDB files 4 | 5 | Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 6 | 7 | Prerequisites 8 | ------------- 9 | 10 | For this program to be useful, you should have you should have the 11 | Digital Mars D Compiler (http://www.digitalmars.com/d/2.0/dmd-windows.html) 12 | and either Microsoft Visual Studio 2005, 2008 or 2010 or one of the Express 13 | versions installed. cv2pdb uses one of the Microsoft DLLs to actually 14 | write the PDB file. 15 | 16 | If you are using some other program, you'll still need some 17 | files from one of the distributions. These are mspdb80.dll, mspdbsrv.exe, 18 | msobj80.dll, mspdbcore.dll and msvcr90.dll from the VS2008 installation or 19 | mspdb100.dll, mspdbsrv.exe, msobj100.dll, mspdbcore.dll and msvcr100.dll 20 | from VS2010. They should be accessible through the PATH environment variable. 21 | (The VS Shell is missing the msobj80.dll/msobj100.dll only). 22 | 23 | Installation 24 | ------------ 25 | You might want to consider installing Visual D (www.dsource.org/projects/visuald) 26 | instead of cv2pdb. Visual D provides both project and language integration 27 | into Visual Studio and comes with an installer that includes cv2pdb. 28 | 29 | There is no full featured installer available for cv2pdb, you'll have 30 | to do some simple manual steps to use cv2pdb. 31 | 32 | 1. The binary package of cv2pdb contains an executable cv2pdb.exe, which 33 | should be copied somewhere accessible through your PATH environment 34 | variable. 35 | 36 | 2. cv2pdb.exe must be able to locate the DLL mspdb80.dll/mspdb100.dll from the Visual 37 | Studio installation. It tries to read the installation path of the latter from the registry, but 38 | if this fails, mspdb80.dll/mspdb100.dll should also be accessible through your PATH 39 | environment variable. 40 | 41 | 3. For best debugging experience, you should configure Visual Studio 42 | to use C/C++ syntax highlighting for D files. This is done by 43 | navigating to the file extensions option page (found in Tools -> Options 44 | -> Text editor -> File Extensions) and adding extensions "d" and "di" 45 | with editor "Microsoft Visual C++". This will also enable display of 46 | variables in the "Auto" watch window. 47 | 48 | 4. You should also add the contents of the files autoexp.expand and 49 | autoexp.visualizer to the respective [AutoExpand] and [Visualizer] 50 | sections of the file autoexp.dat found in 51 | \Common7\Packages\Debugger. 52 | Please note that in a standard installation of Visual Studio, the 53 | section [AutoExpand] is at the beginning of that file, followed by 54 | the section [Visualizer], which extends to the bottom of the file but a few lines 55 | for the section [hresult]. 56 | These lines will enable a convenient display of strings, dynamic arrays, 57 | associative arrays, object types and null references. 58 | 59 | 5. The file dviewhelper.dll must be copied into a directory where 60 | the debugger can find it. This can be any directory accessible through your 61 | PATH variable or \Common7\IDE. Alternatively, 62 | the full path can be specified in the corresponding entries in the 63 | [AutoExpand] section of autoexp.dat. 64 | 65 | 66 | Building from source 67 | -------------------- 68 | The source package comes with a Visual Studio 2008 project and solution 69 | that work with both the Standard and the Express version. These won't 70 | work in VS2005, but creating VS2005 projects should be easy. 71 | 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Artistic License 2.0 2 | 3 | Copyright (c) 2000-2006, The Perl Foundation. 4 | 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | This license establishes the terms under which a given free software 11 | Package may be copied, modified, distributed, and/or redistributed. 12 | The intent is that the Copyright Holder maintains some artistic 13 | control over the development of that Package while still keeping the 14 | Package available as open source and free software. 15 | 16 | You are always permitted to make arrangements wholly outside of this 17 | license directly with the Copyright Holder of a given Package. If the 18 | terms of this license do not permit the full use that you propose to 19 | make of the Package, you should contact the Copyright Holder and seek 20 | a different licensing arrangement. 21 | 22 | Definitions 23 | 24 | "Copyright Holder" means the individual(s) or organization(s) 25 | named in the copyright notice for the entire Package. 26 | 27 | "Contributor" means any party that has contributed code or other 28 | material to the Package, in accordance with the Copyright Holder's 29 | procedures. 30 | 31 | "You" and "your" means any person who would like to copy, 32 | distribute, or modify the Package. 33 | 34 | "Package" means the collection of files distributed by the 35 | Copyright Holder, and derivatives of that collection and/or of 36 | those files. A given Package may consist of either the Standard 37 | Version, or a Modified Version. 38 | 39 | "Distribute" means providing a copy of the Package or making it 40 | accessible to anyone else, or in the case of a company or 41 | organization, to others outside of your company or organization. 42 | 43 | "Distributor Fee" means any fee that you charge for Distributing 44 | this Package or providing support for this Package to another 45 | party. It does not mean licensing fees. 46 | 47 | "Standard Version" refers to the Package if it has not been 48 | modified, or has been modified only in ways explicitly requested 49 | by the Copyright Holder. 50 | 51 | "Modified Version" means the Package, if it has been changed, and 52 | such changes were not explicitly requested by the Copyright 53 | Holder. 54 | 55 | "Original License" means this Artistic License as Distributed with 56 | the Standard Version of the Package, in its current version or as 57 | it may be modified by The Perl Foundation in the future. 58 | 59 | "Source" form means the source code, documentation source, and 60 | configuration files for the Package. 61 | 62 | "Compiled" form means the compiled bytecode, object code, binary, 63 | or any other form resulting from mechanical transformation or 64 | translation of the Source form. 65 | 66 | 67 | Permission for Use and Modification Without Distribution 68 | 69 | (1) You are permitted to use the Standard Version and create and use 70 | Modified Versions for any purpose without restriction, provided that 71 | you do not Distribute the Modified Version. 72 | 73 | 74 | Permissions for Redistribution of the Standard Version 75 | 76 | (2) You may Distribute verbatim copies of the Source form of the 77 | Standard Version of this Package in any medium without restriction, 78 | either gratis or for a Distributor Fee, provided that you duplicate 79 | all of the original copyright notices and associated disclaimers. At 80 | your discretion, such verbatim copies may or may not include a 81 | Compiled form of the Package. 82 | 83 | (3) You may apply any bug fixes, portability changes, and other 84 | modifications made available from the Copyright Holder. The resulting 85 | Package will still be considered the Standard Version, and as such 86 | will be subject to the Original License. 87 | 88 | 89 | Distribution of Modified Versions of the Package as Source 90 | 91 | (4) You may Distribute your Modified Version as Source (either gratis 92 | or for a Distributor Fee, and with or without a Compiled form of the 93 | Modified Version) provided that you clearly document how it differs 94 | from the Standard Version, including, but not limited to, documenting 95 | any non-standard features, executables, or modules, and provided that 96 | you do at least ONE of the following: 97 | 98 | (a) make the Modified Version available to the Copyright Holder 99 | of the Standard Version, under the Original License, so that the 100 | Copyright Holder may include your modifications in the Standard 101 | Version. 102 | 103 | (b) ensure that installation of your Modified Version does not 104 | prevent the user installing or running the Standard Version. In 105 | addition, the Modified Version must bear a name that is different 106 | from the name of the Standard Version. 107 | 108 | (c) allow anyone who receives a copy of the Modified Version to 109 | make the Source form of the Modified Version available to others 110 | under 111 | 112 | (i) the Original License or 113 | 114 | (ii) a license that permits the licensee to freely copy, 115 | modify and redistribute the Modified Version using the same 116 | licensing terms that apply to the copy that the licensee 117 | received, and requires that the Source form of the Modified 118 | Version, and of any works derived from it, be made freely 119 | available in that license fees are prohibited but Distributor 120 | Fees are allowed. 121 | 122 | 123 | Distribution of Compiled Forms of the Standard Version 124 | or Modified Versions without the Source 125 | 126 | (5) You may Distribute Compiled forms of the Standard Version without 127 | the Source, provided that you include complete instructions on how to 128 | get the Source of the Standard Version. Such instructions must be 129 | valid at the time of your distribution. If these instructions, at any 130 | time while you are carrying out such distribution, become invalid, you 131 | must provide new instructions on demand or cease further distribution. 132 | If you provide valid instructions or cease distribution within thirty 133 | days after you become aware that the instructions are invalid, then 134 | you do not forfeit any of your rights under this license. 135 | 136 | (6) You may Distribute a Modified Version in Compiled form without 137 | the Source, provided that you comply with Section 4 with respect to 138 | the Source of the Modified Version. 139 | 140 | 141 | Aggregating or Linking the Package 142 | 143 | (7) You may aggregate the Package (either the Standard Version or 144 | Modified Version) with other packages and Distribute the resulting 145 | aggregation provided that you do not charge a licensing fee for the 146 | Package. Distributor Fees are permitted, and licensing fees for other 147 | components in the aggregation are permitted. The terms of this license 148 | apply to the use and Distribution of the Standard or Modified Versions 149 | as included in the aggregation. 150 | 151 | (8) You are permitted to link Modified and Standard Versions with 152 | other works, to embed the Package in a larger work of your own, or to 153 | build stand-alone binary or bytecode versions of applications that 154 | include the Package, and Distribute the result without restriction, 155 | provided the result does not expose a direct interface to the Package. 156 | 157 | 158 | Items That are Not Considered Part of a Modified Version 159 | 160 | (9) Works (including, but not limited to, modules and scripts) that 161 | merely extend or make use of the Package, do not, by themselves, cause 162 | the Package to be a Modified Version. In addition, such works are not 163 | considered parts of the Package itself, and are not subject to the 164 | terms of this license. 165 | 166 | 167 | General Provisions 168 | 169 | (10) Any use, modification, and distribution of the Standard or 170 | Modified Versions is governed by this Artistic License. By using, 171 | modifying or distributing the Package, you accept this license. Do not 172 | use, modify, or distribute the Package, if you do not accept this 173 | license. 174 | 175 | (11) If your Modified Version has been derived from a Modified 176 | Version made by someone other than you, you are nevertheless required 177 | to ensure that your Modified Version complies with the requirements of 178 | this license. 179 | 180 | (12) This license does not grant you the right to use any trademark, 181 | service mark, tradename, or logo of the Copyright Holder. 182 | 183 | (13) This license includes the non-exclusive, worldwide, 184 | free-of-charge patent license to make, have made, use, offer to sell, 185 | sell, import and otherwise transfer the Package with respect to any 186 | patent claims licensable by the Copyright Holder that are necessarily 187 | infringed by the Package. If you institute patent litigation 188 | (including a cross-claim or counterclaim) against any party alleging 189 | that the Package constitutes direct or contributory patent 190 | infringement, then this Artistic License to you shall terminate on the 191 | date that such litigation is filed. 192 | 193 | (14) Disclaimer of Warranty: 194 | THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS 195 | IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED 196 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 197 | NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL 198 | LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL 199 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 200 | DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF 201 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # makefile to be used with NMAKE for building source and 3 | # installation packages 4 | # 5 | # prerequisites: 6 | # - environment variable VSINSTALLDIR must point to your Visual Studio 7 | # or VCExpress installation folder 8 | # - Info-zip must be found in the PATH 9 | # 10 | # run 11 | # nmake src 12 | # to create a source package with name cv2pdb_src_.zip in 13 | # ..\downloads 14 | # 15 | # run 16 | # nmake bin 17 | # to create a binary package with name cv2pdb_.zip in 18 | # ..\downloads 19 | 20 | SRC = src\cv2pdb.cpp \ 21 | src\cv2pdb.h \ 22 | src\demangle.cpp \ 23 | src\demangle.h \ 24 | src\dwarf2pdb.cpp \ 25 | src\dwarf.h \ 26 | src\LastError.h \ 27 | src\main.cpp \ 28 | src\mscvpdb.h \ 29 | src\mspdb.h \ 30 | src\mspdb.cpp \ 31 | src\PEImage.cpp \ 32 | src\PEImage.h \ 33 | src\symutil.cpp \ 34 | src\symutil.h \ 35 | src\dviewhelper\dviewhelper.cpp 36 | 37 | ADD = Makefile \ 38 | src\cv2pdb.vcproj \ 39 | src\dviewhelper\dviewhelper.vcproj \ 40 | src\cv2pdb.sln 41 | 42 | DOC = VERSION README INSTALL LICENSE CHANGES TODO FEATURES autoexp.expand autoexp.visualizer 43 | 44 | BIN = bin\Release\cv2pdb.exe bin\Release\dviewhelper.dll 45 | 46 | TEST = test\cvtest.d \ 47 | test\cvtest.vcproj \ 48 | test\Makefile \ 49 | 50 | all: bin src 51 | 52 | ############################### 53 | include VERSION 54 | 55 | DOWNLOADS = ..\downloads 56 | 57 | $(DOWNLOADS): 58 | if not exist $(DOWNLOADS)\nul mkdir $(DOWNLOADS) 59 | 60 | ############################### 61 | ZIP = zip 62 | SRC_ZIP = $(DOWNLOADS)\cv2pdb_src_$(VERSION).zip 63 | 64 | src: $(DOWNLOADS) $(SRC_ZIP) 65 | 66 | $(SRC_ZIP): $(SRC) $(ADD) $(DOC) $(TEST) 67 | if exist $(SRC_ZIP) del $(SRC_ZIP) 68 | $(ZIP) $(SRC_ZIP) -X $(SRC) $(ADD) $(DOC) $(TEST) 69 | 70 | ############################### 71 | BIN_ZIP = $(DOWNLOADS)\cv2pdb_$(VERSION).zip 72 | 73 | bin: $(DOWNLOADS) $(BIN_ZIP) 74 | 75 | $(BIN_ZIP): $(BIN) $(DOC) Makefile 76 | if exist $(BIN_ZIP) del $(BIN_ZIP) 77 | $(ZIP) $(BIN_ZIP) -j -X $(BIN) $(DOC) 78 | 79 | IDEDIR = $(VSINSTALLDIR)\Common7\IDE 80 | 81 | $(BIN): $(SRC) $(ADD) $(TEST) VERSION 82 | if exist "$(IDEDIR)\VCExpress.exe" "$(IDEDIR)\VCExpress.exe" /Build Release src\cv2pdb.sln 83 | if not exist "$(IDEDIR)\VCExpress.exe" "$(IDEDIR)\devenv.exe" /Build Release src\cv2pdb.sln 84 | 85 | ############################### 86 | cv2pdb_exe: 87 | devenv /Project "cv2pdb" /Build "Release|Win32" src\cv2pdb_vs12.sln 88 | 89 | test: cv2pdb_exe 90 | cd ..\test && nmake test 91 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | 2 | This is the README file for cv2pdb, a 3 | converter of DMD CodeView/DWARF debug information to PDB files 4 | 5 | Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 6 | 7 | The goal of this project is to make debugging of D applications that 8 | were created with the Digital Mars DMD compiler, as seamless as possible 9 | in current versions of Visual Studio (i.e Visual Studio 2008 and 10 | VCExpress). 11 | As a side effect, other applications might also benefit from the 12 | converted debug information, like WinDbg or DMC. 13 | 14 | Features 15 | -------- 16 | * conversion of DMD CodeView information to PDB file 17 | * conversion of DWARF information to PDB file 18 | * converted line number info allows setting breakpoints 19 | * display of variables, fields and objects in watch, local and auto window and in data tooltips 20 | * generates generic debug info for dynamic arrays, associative arrays and delegates 21 | * autoexp.dat allows convenient display of dynamic and associative arrays in watch windows 22 | * demangles function names for convenient display of callstack 23 | * also works debugging executables built with the Digital Mars C/C++ compiler DMC 24 | 25 | License information 26 | ------------------- 27 | 28 | This code is distributed under the term of the Artistic License 2.0. 29 | For more details, see the full text of the license in the file LICENSE. 30 | 31 | The file demangle.cpp is an adaption of denangle.d to C++ distributed with 32 | the DMD compiler. It is placed into the Public Domain. 33 | 34 | The file mscvpdb.h is taken from the WINE-project (http://www.winehq.org) 35 | and is distributed under the terms of the GNU Lesser General Public 36 | License as published by the Free Software Foundation; either 37 | version 2.1 of the License, or (at your option) any later version. 38 | See the file header for more details and 39 | http://www.gnu.org/licenses/lgpl.html for the full license. 40 | 41 | The file dwarf.h is taken from the libdwarf project 42 | (http://reality.sgiweb.org/davea/dwarf.html) 43 | and is distributed under the terms of the GNU Lesser General Public 44 | License as published by the Free Software Foundation; either 45 | version 2.1 of the License, or (at your option) any later version. 46 | See the file header for more details and 47 | http://www.gnu.org/licenses/lgpl.html for the full license. 48 | 49 | Installation 50 | ------------ 51 | Sorry, there is no full featured installer available yet, you'll have 52 | to do some simple manual steps to use cv2pdb. 53 | 54 | See the file INSTALL for further details. 55 | 56 | Usage 57 | ----- 58 | 59 | Quick start: 60 | 61 | Simply run 62 | 63 | cv2pdb debuggee.exe 64 | 65 | on your executable to debug and start the debugger, e.g. 66 | 67 | devenv debuggee.exe 68 | 69 | or 70 | 71 | vcexpress debuggee.exe 72 | 73 | Description: 74 | ------------ 75 | 76 | cv2pdb.exe is a command line tool which outputs its usage information 77 | if run without arguments: 78 | 79 | usage: cv2pdb [-D|-C|-n|-e|-s|-p|-l] [new-exe-file] [pdb-file] 80 | 81 | With the `-D` option, you can specify the version of the DMD compiler 82 | you are using. Unfortunately, this information is not embedded into 83 | the debug information. The default is -D2.072. So far, this information 84 | is only needed to determine whether "char[]" or "const char[]" is 85 | translated to "string". 86 | 87 | Starting with DMD 2.043, assoiciative arrays have a slightly different 88 | implementation, so debug information needs to be adjusted aswell. This changed 89 | again with DMD 2.068. Version 2.072 started embedding source language 'D' into object files. 90 | Use -D 2.043 or higher to produce the matching debug info. 91 | 92 | Option `-C` tells the program, that you want to debug a program compiled 93 | with DMC, the Digital Mars C/C++ compiler. It will disable some of the 94 | D specific functions and will enable adjustment of stack variable names. 95 | 96 | With option `-n` demangling of symbols is disabled. 97 | 98 | Older versions of the Visual Studio Debugger (up to VS 2012) don't work well if type 99 | and symbol names contain `.`. That's why cv2pdb replaces these characters with '@' by default. 100 | This character can be configured to another character with the `-s`, so `-s.` will 101 | keep symbol names as emitted by the compiler. 102 | 103 | The first file name on the command line is expected to be the executable 104 | or dynamic library compiled by the DMD compiler and containing the 105 | CodeView debug information (-g option used when running dmd). 106 | 107 | If no further file name is given, a PDB file will be created with the 108 | same base name as the executable, but with extension "pdb", and the 109 | executable will be modified to redirect debuggers to this pdb-file instead 110 | of the original debug information. 111 | 112 | Example: 113 | 114 | cv2pdb debuggee.exe 115 | 116 | In an environment using make-like tools, it is often useful to create 117 | a new file instead of modifying existing files. That way the file 118 | modification time can be used to continue the build process at the 119 | correct step. 120 | If another file name is specified, the new executable is written 121 | to this file and leaves the input executable unmodified.. The naming 122 | of the pdb-file will use the base name of the output file. 123 | 124 | Example: 125 | 126 | cv2pdb debuggee.exe debuggee_pdb.exe 127 | 128 | Last but not least, the resulting pdb-file can be renamed by specifying 129 | a third file name. 130 | 131 | Example: 132 | 133 | cv2pdb debuggee.exe debuggee_pdb.exe debug.pdb 134 | 135 | If you plan to move the excutable and PDB file to another computer, it might be helpful 136 | to change the path or file reference that is embedded into the converted binary. `-p` allows 137 | to replace the absolute path of the PDB file with any other file name irrespective of the 138 | actually generated PDB file and without making the file reference absolute. 139 | 140 | If the debug information is located in a separate file, use the `-l` option to specify 141 | a link to the file with the debug information. If the image has the `.gnu_debuglink` section, 142 | the link will be retrieved from the section and the `-l` option is not required. 143 | The debug information file will be loaded from the same directory where the image file is located. 144 | If there is no file there, it will be loaded from `.debug` subdirectory. 145 | 146 | Example: 147 | 148 | cv2pdb -ldebuggee.debug debuggee.exe 149 | 150 | Changes 151 | ------- 152 | 153 | For documentation on the changes between this version and 154 | previous versions, please see the file CHANGES. 155 | 156 | Feedback 157 | -------- 158 | The project home for cv2pdb is here: 159 | 160 | https://github.com/rainers/cv2pdb 161 | 162 | There's an issue tracker, where you can leave your comments and suggestions. 163 | 164 | Have fun, 165 | Rainer Schuetze 166 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | This is the TODO file for cv2pdb, a 3 | converter of DMD CodeView/DWARF debug information to PDB files 4 | 5 | Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 6 | 7 | There are some quirks that you might run into when using 8 | Visual Studio to debug D programs. These will hopefully be removed 9 | in the future, but not all have a known solution. 10 | 11 | * has to use '@' instead of '.' in class names to avoid confusing debugger, 12 | but it looks ugly 13 | * "this.var" is not a valid debugger expression, you have to use 14 | "var" or "this->var" 15 | * global/static vars have to be watched with full module and class name 16 | specified (e.g. module@globvar) 17 | * type of associative arrays is displayed as aa<*> to allow overload 18 | in autoexp.dat 19 | * DMD does not emit different debug information for const and invariant, 20 | type info is the same 21 | * DMD does not emit different debug information for float and ifloat, 22 | type info is the same 23 | * type display of delegate does not have arguments 24 | * assoc_array.length cannot be displayed (it is assoc_array.a->nodes) 25 | * enum values not displayed 26 | * watch incorrect if same variable name used in different parts of a function 27 | * line number in templates sometimes off by 1 or 2 28 | * call to other function jumps to called function while pushing default arguments 29 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | VERSION = 0.53 2 | -------------------------------------------------------------------------------- /autoexp.expand: -------------------------------------------------------------------------------- 1 | ;; added to [AutoExpand] for cv2pdb - keep this line for uninstaller 2 | ;; add DO NOT REMOVE to the line above after the '-' to not remove/update 3 | ;; this section by the installer/uninstaller 4 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 5 | ;; load helper dll dviewhelper.dll to display D strings 6 | ;; 7 | ;; add the following lines to the [AutoExpand] section 8 | ;; 9 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 10 | 11 | object_viewhelper=$ADDIN(dviewhelper.dll,_DObjectView@28) 12 | object@Object=$ADDIN(dviewhelper.dll,_DObjectView@28) 13 | string=$ADDIN(dviewhelper.dll,_DStringView@28) 14 | wstring=$ADDIN(dviewhelper.dll,_DWStringView@28) 15 | dstring=$ADDIN(dviewhelper.dll,_DDStringView@28) 16 | char[]=$ADDIN(dviewhelper.dll,_DStringView@28) 17 | wchar[]=$ADDIN(dviewhelper.dll,_DWStringView@28) 18 | dchar[]=$ADDIN(dviewhelper.dll,_DDStringView@28) 19 | const(char)[]=$ADDIN(dviewhelper.dll,_DStringView@28) 20 | const(wchar)[]=$ADDIN(dviewhelper.dll,_DWStringView@28) 21 | const(dchar)[]=$ADDIN(dviewhelper.dll,_DDStringView@28) 22 | const(char[])=$ADDIN(dviewhelper.dll,_DStringView@28) 23 | const(wchar[])=$ADDIN(dviewhelper.dll,_DWStringView@28) 24 | const(dchar[])=$ADDIN(dviewhelper.dll,_DDStringView@28) 25 | immutable(char)[]=$ADDIN(dviewhelper.dll,_DStringView@28) 26 | immutable(wchar)[]=$ADDIN(dviewhelper.dll,_DWStringView@28) 27 | immutable(dchar)[]=$ADDIN(dviewhelper.dll,_DDStringView@28) 28 | immutable(char[])=$ADDIN(dviewhelper.dll,_DStringView@28) 29 | immutable(wchar[])=$ADDIN(dviewhelper.dll,_DWStringView@28) 30 | immutable(dchar[])=$ADDIN(dviewhelper.dll,_DDStringView@28) 31 | 32 | ;; eo section AutoExpand for D variables ;;;;;;;;;;;;;;;;;;;;;; 33 | ;; eo added for cv2pdb - keep this line for uninstaller 34 | -------------------------------------------------------------------------------- /autoexp.visualizer: -------------------------------------------------------------------------------- 1 | ;; added to [Visualizer] for cv2pdb - keep this line for uninstaller 2 | ;; add DO NOT REMOVE to the line above after the '-' to not remove/update 3 | ;; this section by the installer/uninstaller 4 | 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | ;; D types visualizer 7 | ;; 8 | ;; add the remainder of this file to the [Visualizer] section 9 | ;; 10 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 11 | 12 | ; strings not as dynamic arrays, use dviewhelper instead 13 | char[]|const(char)[]|immutable(char)[] { 14 | preview ( [(string)$e] ) 15 | } 16 | 17 | wchar[]|const(wchar)[]|immutable(wchar)[] { 18 | preview ( [(wstring)$e] ) 19 | } 20 | 21 | dchar[]|const(dchar)[]|immutable(dchar)[] { 22 | preview ( [(dstring)$e] ) 23 | } 24 | 25 | const void[]|void[] { 26 | preview ( 27 | #if ($e.ptr == 0) ( "null" ) 28 | #elif($e.length > 4096) ( 29 | #( "[", $e.length, "] ", (void*) $e.ptr, " too large for expansion" ) 30 | ) 31 | #elif($e.length > 64) ( 32 | #( "[", $e.length, "]( ", 33 | #array( expr:((unsigned char*)$e.ptr)[$i], size:64 ), 34 | ",...)" 35 | ) 36 | ) 37 | #else ( 38 | #( 39 | "[", $e.length, "](", 40 | #array ( expr : ((unsigned char*)$e.ptr)[$i], size : $e.length ), 41 | ")" 42 | ) 43 | ) 44 | ) 45 | children ( 46 | #if($e.length > 4096) ( 47 | #( 48 | length: [$e.length], 49 | ptr: [(void*) $e.ptr] 50 | ) 51 | ) 52 | #else ( 53 | #( 54 | length: [$e.length], 55 | #array ( 56 | expr: ((unsigned char*)$e.ptr)[$i], 57 | size: $e.length 58 | ) 59 | ) 60 | ) 61 | ) 62 | } 63 | 64 | ; dynamic array 65 | *[]|dArray* { 66 | preview ( 67 | #if ($e.ptr == 0) ( "null" ) 68 | #elif($e.length > 4096) ( 69 | #( "[", $e.length, "] ", (void*) $e.ptr, " too large for expansion" ) 70 | ) 71 | #elif($e.length > 64) ( 72 | #( "[", $e.length, "]( ", 73 | #array( expr:($e.ptr)[$i], size:64 ), 74 | ",...)" 75 | ) 76 | ) 77 | #else ( 78 | #( 79 | "[", $e.length, "](", 80 | #array ( expr : ($e.ptr)[$i], size : $e.length ), 81 | ")" 82 | ) 83 | ) 84 | ) 85 | children ( 86 | #if($e.length > 4096) ( 87 | #( 88 | length: [$e.length], 89 | ptr: [$e.ptr] 90 | ) 91 | ) 92 | #else ( 93 | #( 94 | length: [$e.length], 95 | #array ( 96 | expr: $e.ptr[$i], 97 | size: $e.length 98 | ) 99 | ) 100 | ) 101 | ) 102 | } 103 | 104 | ;; display associative array 105 | ;; 106 | ;; the "magic" sizes of the basic dynamic array are used to check for uninitialized 107 | ;; arrays 108 | ;; 97UL, 389UL, 109 | ;; 1_543UL, 6_151UL, 110 | ;; 24_593UL, 98_317UL, 111 | ;; 393_241UL, 1_572_869UL, 112 | ;; 6_291_469UL, 25_165_843UL, 113 | ;; 100_663_319UL, 402_653_189UL, 114 | ;; 1_610_612_741UL, 4_294_967_291UL, 115 | aa<*> { 116 | preview( 117 | #if($e.a == 0 || $e.a->b.ptr == 0) ( "null" ) 118 | ; expressions must be in a single line (sigh) 119 | #elif($e.a->b.length == 97 || $e.a->b.length == 389 || $e.a->b.length == 1543 || $e.a->b.length == 6151 || $e.a->b.length == 24593 || $e.a->b.length == 98317 || $e.a->b.length == 393241 || $e.a->b.length == 1572869 || $e.a->b.length == 6291469 || $e.a->b.length == 25165843) 120 | ( 121 | #if($e.a->nodes > 1024) ( 122 | #( "[", $e.a->nodes, "] ", [(void*) $e.a], " too large for expansion" ) 123 | ) 124 | #else ( 125 | #( "[", $e.a->nodes, "] ", [(void*) $e.a] ) 126 | ) 127 | ) 128 | #elif (1) ; no #else in a series of #elif !? 129 | ( 130 | #( "[", $e.a->nodes, "] ", [(void*) $e.a], " uninitialized" ) 131 | ) 132 | ) 133 | children( 134 | #if($e.a == 0 || $e.a->b.ptr == 0 || $e.a->nodes > 1024) 135 | ( #array( expr: 0, size: 0 ) ) 136 | #else ( 137 | #( 138 | #array ( 139 | expr: &$e.a->b.ptr[$i], 140 | size: $e.a->b.length 141 | ) : 142 | #tree ( 143 | head : $e, 144 | left : left, 145 | right : right 146 | ; limit size for sanity, hope rehashing takes care of not long lists 147 | ; limiting the number does not work, it will try to show the given number of elements 148 | ; size : 32 149 | ) : $e 150 | ) 151 | ) 152 | ) 153 | } 154 | 155 | ;; display associative array (starting with with dmd2.043, new sizes 4 and 31 were added, and 156 | ;; a list is used per hash entry instead of a tree 157 | ;; remember to pass -D 2.043 to cv2pdb to produce suitable debug info 158 | ;; 159 | aa2<*> { 160 | preview( 161 | #if($e.a == 0 || $e.a->b.ptr == 0) ( "null" ) 162 | ; expressions must be in a single line (sigh) 163 | #elif($e.a->b.length == 4 || $e.a->b.length == 31 || $e.a->b.length == 97 || $e.a->b.length == 389 || $e.a->b.length == 1543 || $e.a->b.length == 6151 || $e.a->b.length == 24593 || $e.a->b.length == 98317 || $e.a->b.length == 393241 || $e.a->b.length == 1572869 || $e.a->b.length == 6291469 || $e.a->b.length == 25165843) 164 | ( 165 | #if($e.a->nodes > 1024) ( 166 | #( "[", $e.a->nodes, "] ", [(void*) $e.a], " too large for expansion" ) 167 | ) 168 | #else ( 169 | #( "[", $e.a->nodes, "] ", [(void*) $e.a] ) 170 | ) 171 | ) 172 | #elif (1) ; no #else in a series of #elif !? 173 | ( 174 | #( "[", $e.a->nodes, "] ", [(void*) $e.a], " uninitialized" ) 175 | ) 176 | ) 177 | children( 178 | #if($e.a == 0 || $e.a->b.ptr == 0) 179 | ( #array( expr: 0, size: 0 ) ) 180 | ; expressions must be in a single line (sigh) 181 | #elif($e.a->b.length == 4 || $e.a->b.length == 31 || $e.a->b.length == 97 || $e.a->b.length == 389 || $e.a->b.length == 1543 || $e.a->b.length == 6151 || $e.a->b.length == 24593 || $e.a->b.length == 98317 || $e.a->b.length == 393241 || $e.a->b.length == 1572869 || $e.a->b.length == 6291469 || $e.a->b.length == 25165843) 182 | ( 183 | #( 184 | #array ( 185 | expr: &$e.a->b.ptr[$i], 186 | size: $e.a->b.length 187 | ) : 188 | ; DMD 2.043+ 189 | #list ( 190 | head : $e, 191 | next : next 192 | ; limit size for sanity, hope rehashing takes care of not long lists 193 | ; limiting the number does not work, it will try to show the given number of elements 194 | ; size : 32 195 | ) : $e 196 | ) 197 | ) 198 | #elif (1) ; no #else in a series of #elif !? 199 | ( 200 | #( "[", $e.a->nodes, "] ", [(void*) $e.a], " uninitialized" ) 201 | ) 202 | ) 203 | } 204 | 205 | ; display tree 206 | internal@aaA<*,*> { 207 | preview( 208 | #( "<", $e.key, ", ", $e.value, ">" ) 209 | ) 210 | children ( 211 | #( 212 | key: [$e.key], 213 | value: [$e.value] 214 | ) 215 | ) 216 | } 217 | 218 | ; display null references and class name for class objects 219 | *@* { 220 | preview( 221 | #( 222 | #if (&$e == 0) ( "null" ) 223 | #elif ($e.__classtype == 1) ( ;;; classes 224 | #( "[", [$e.__viewhelper], "] ", [$e,!] ) 225 | ) 226 | #elif ($e.__classtype == 2) ( ;;; DInterface 227 | #( "[D-Interface ", [**(object_viewhelper**)&$e], "] " ) 228 | ) 229 | #elif ($e.__classtype == 3) ( ;;; CppInterface 230 | #( "[C++Interface]") 231 | ) 232 | #elif ($e.__classtype == 4) ( ;;; Struct 233 | #( [$e,!] ) 234 | ) 235 | #elif (1) ( 236 | #( [$e,!] ) 237 | ) 238 | ) 239 | ) 240 | } 241 | 242 | ;; eo section Visualizer for D variables ;;;;;;;;;;;;;;;;;;;;;; 243 | ;; eo added for cv2pdb - keep this line for uninstaller 244 | -------------------------------------------------------------------------------- /src/LastError.h: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #ifndef __LASTERROR_H__ 8 | #define __LASTERROR_H__ 9 | 10 | class LastError 11 | { 12 | public: 13 | LastError() : lastError("") {} 14 | 15 | bool setError(const char* msg) { lastError = msg; return false; } 16 | const char* getLastError() const { return lastError; } 17 | bool hadError() const { return lastError != 0 && *lastError; } 18 | 19 | private: 20 | const char* lastError; 21 | }; 22 | 23 | 24 | #endif //__LASTERROR_H__ -------------------------------------------------------------------------------- /src/NatvisFile.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tag={tag} code={code} {name,s} 5 | 6 | 7 | 8 | 9 | children 10 | next 11 | this 12 | 13 | 14 | 15 | 16 | 17 | 18 | next 19 | next 20 | this 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/PEImage.h: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #ifndef __PEIMAGE_H__ 8 | #define __PEIMAGE_H__ 9 | 10 | #include "LastError.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | struct OMFDirHeader; 17 | struct OMFDirEntry; 18 | 19 | typedef unsigned char byte; 20 | 21 | struct SymbolInfo 22 | { 23 | int seg; 24 | unsigned long off; 25 | bool dllimport; 26 | }; 27 | 28 | struct PESection 29 | { 30 | byte* base; 31 | unsigned long length; 32 | unsigned int secNo; 33 | 34 | PESection() 35 | : base(0) 36 | , length(0) 37 | , secNo(0) 38 | { 39 | } 40 | 41 | byte* byteAt(unsigned int off) const 42 | { 43 | return base + off; 44 | } 45 | 46 | byte* startByte() const 47 | { 48 | return byteAt(0); 49 | } 50 | 51 | byte* endByte() const 52 | { 53 | return byteAt(0) + length; 54 | } 55 | 56 | bool isPresent() const 57 | { 58 | return base && length; 59 | } 60 | 61 | bool isPtrInside(const void *p) const 62 | { 63 | auto pInt = (uintptr_t)p; 64 | return (pInt >= (uintptr_t)base && pInt < (uintptr_t)base + length); 65 | } 66 | 67 | unsigned int sectOff(void *p) const 68 | { 69 | return (unsigned int)((uintptr_t)p - (uintptr_t)base); 70 | } 71 | }; 72 | 73 | // Define the list of interesting PE sections in one place so that we can 74 | // generate definitions needed to populate our pointers and reference each 75 | // section. 76 | 77 | #define SECTION_LIST() \ 78 | EXPANDSEC(debug_addr) \ 79 | EXPANDSEC(debug_info) \ 80 | EXPANDSEC(debug_abbrev) \ 81 | EXPANDSEC(debug_line) \ 82 | EXPANDSEC(debug_line_str) \ 83 | EXPANDSEC(debug_frame) \ 84 | EXPANDSEC(debug_str) \ 85 | EXPANDSEC(debug_str_offsets) \ 86 | EXPANDSEC(debug_loc) \ 87 | EXPANDSEC(debug_loclists) \ 88 | EXPANDSEC(debug_ranges) \ 89 | EXPANDSEC(debug_rnglists) \ 90 | EXPANDSEC(gnu_debuglink) \ 91 | EXPANDSEC(reloc) \ 92 | EXPANDSEC(text) 93 | 94 | 95 | #define IMGHDR(x) (hdr32 ? hdr32->x : hdr64->x) 96 | 97 | class PEImage : public LastError 98 | { 99 | public: 100 | PEImage(const TCHAR* iname = 0); 101 | ~PEImage(); 102 | 103 | template P* DP(int off) const 104 | { 105 | return (P*) ((char*) dump_base + off); 106 | } 107 | template P* DPV(int off, int size) const 108 | { 109 | if(off < 0 || off + size > dump_total_len) 110 | return 0; 111 | return (P*) ((char*) dump_base + off); 112 | } 113 | template P* DPV(int off) const 114 | { 115 | return DPV

(off, sizeof(P)); 116 | } 117 | template P* CVP(int off) const 118 | { 119 | return DPV

(cv_base + off, sizeof(P)); 120 | } 121 | 122 | template P* RVA(unsigned long rva, int len) 123 | { 124 | IMAGE_DOS_HEADER *dos = DPV (0); 125 | IMAGE_NT_HEADERS32* hdr = DPV (dos->e_lfanew); 126 | IMAGE_SECTION_HEADER* sec = IMAGE_FIRST_SECTION(hdr); 127 | 128 | for (int i = 0; i < hdr->FileHeader.NumberOfSections; i++) 129 | { 130 | if (rva >= sec[i].VirtualAddress && 131 | rva + len <= sec[i].VirtualAddress + sec[i].SizeOfRawData) 132 | return DPV

(sec[i].PointerToRawData + rva - sec[i].VirtualAddress, len); 133 | } 134 | return 0; 135 | } 136 | 137 | bool readAll(const TCHAR* iname); 138 | bool loadExe(const TCHAR* iname); 139 | bool loadObj(const TCHAR* iname); 140 | bool save(const TCHAR* oname); 141 | 142 | bool replaceDebugSection (const void* data, int datalen, bool initCV); 143 | void initSec(PESection& peSec, int secNo) const; 144 | bool initCVPtr(bool initDbgDir); 145 | bool initDbgPtr(bool initDbgDir); 146 | bool initDWARFPtr(bool initDbgDir); 147 | bool initDWARFObject(); 148 | void initDWARFSegments(); 149 | bool relocateDebugLineInfo(unsigned int img_base); 150 | 151 | bool hasDWARF() const { return debug_line.isPresent(); } 152 | bool hasDebugLink() const { return gnu_debuglink.isPresent(); } 153 | bool isX64() const { return x64; } 154 | bool isDBG() const { return dbgfile; } 155 | 156 | int countCVEntries() const; 157 | OMFDirEntry* getCVEntry(int i) const; 158 | 159 | int getCVSize() const { return dbgDir->SizeOfData; } 160 | 161 | // utilities 162 | static void* alloc_aligned(unsigned int size, unsigned int align, unsigned int alignoff = 0); 163 | static void free_aligned(void* p); 164 | 165 | int countSections() const { return nsec; } 166 | int findSection(unsigned int off) const; 167 | int findSymbol(const char* name, unsigned long& off, bool& dllimport) const; 168 | const char* findSectionSymbolName(int s) const; 169 | const IMAGE_SECTION_HEADER& getSection(int s) const { return sec[s]; } 170 | unsigned long long getImageBase() const { return IMGHDR(OptionalHeader.ImageBase); } 171 | int getRelocationInLineSegment(unsigned int offset) const; 172 | int getRelocationInSegment(int segment, unsigned int offset) const; 173 | 174 | int dumpDebugLineInfoCOFF() const; 175 | int dumpDebugLineInfoOMF() const; 176 | void createSymbolCache() const; 177 | 178 | const char* getStrTable() const { return strtable; }; 179 | 180 | private: 181 | bool _initFromCVDebugDir(IMAGE_DEBUG_DIRECTORY* ddir); 182 | 183 | template const char* t_findSectionSymbolName(int s) const; 184 | 185 | // File handle to PE image. 186 | int fd; 187 | 188 | // Pointer to in-memory buffer containing loaded PE image. 189 | void* dump_base; 190 | 191 | // Size of `dump_base` in bytes. 192 | int dump_total_len; 193 | 194 | // codeview fields 195 | IMAGE_DOS_HEADER *dos; 196 | IMAGE_NT_HEADERS32* hdr32; 197 | IMAGE_NT_HEADERS64* hdr64; 198 | IMAGE_SECTION_HEADER* sec; 199 | IMAGE_DEBUG_DIRECTORY* dbgDir; 200 | OMFDirHeader* dirHeader; 201 | OMFDirEntry* dirEntry; 202 | int nsec; 203 | int nsym; 204 | const char* symtable; 205 | const char* strtable; 206 | bool x64; // targets 64-bit machine 207 | bool bigobj; 208 | bool dbgfile; // is DBG file 209 | mutable std::unordered_map symbolCache; 210 | 211 | public: 212 | // dwarf fields 213 | // List of DWARF section descriptors. 214 | #define EXPANDSEC(name) PESection name; 215 | SECTION_LIST() 216 | #undef EXPANDSEC 217 | 218 | int cv_base; 219 | }; 220 | 221 | struct SectionDescriptor { 222 | const char *name; 223 | PESection PEImage::* pSec; 224 | }; 225 | 226 | #define EXPANDSEC(name) constexpr SectionDescriptor sec_desc_##name { "." #name, &PEImage::name }; 227 | SECTION_LIST() 228 | #undef EXPANDSEC 229 | 230 | constexpr const SectionDescriptor *sec_descriptors[] = 231 | { 232 | #define EXPANDSEC(name) &sec_desc_##name, 233 | SECTION_LIST() 234 | #undef EXPANDSEC 235 | }; 236 | 237 | 238 | #undef SECTION_LIST 239 | 240 | #endif //__PEIMAGE_H__ 241 | -------------------------------------------------------------------------------- /src/cv2pdb.h: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #ifndef __CV2PDB_H__ 8 | #define __CV2PDB_H__ 9 | 10 | #include 11 | 12 | #include "LastError.h" 13 | #include "mspdb.h" 14 | #include "readDwarf.h" 15 | 16 | #include 17 | #include 18 | 19 | extern "C" { 20 | #include "mscvpdb.h" 21 | #include "dcvinfo.h" 22 | } 23 | 24 | class PEImage; 25 | struct DWARF_InfoData; 26 | struct DWARF_CompilationUnit; 27 | class CFIIndex; 28 | 29 | class CV2PDB : public LastError 30 | { 31 | public: 32 | CV2PDB(PEImage& image, PEImage* imageDWARF, DebugLevel debug); 33 | ~CV2PDB(); 34 | 35 | bool cleanup(bool commit); 36 | bool openPDB(const TCHAR* pdbname, const TCHAR* pdbref); 37 | 38 | bool setError(const char* msg); 39 | bool createModules(); 40 | 41 | bool initLibraries(); 42 | const BYTE* getLibrary(int i); 43 | bool initSegMap(); 44 | 45 | enum 46 | { 47 | kCmdAdd, 48 | kCmdCount, 49 | kCmdNestedTypes, 50 | kCmdOffsetFirstVirtualMethod, 51 | kCmdHasClassTypeEnum, 52 | kCmdCountBaseClasses 53 | }; 54 | int _doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reftype* fieldlist, int arg); 55 | int addFields(codeview_reftype* dfieldlist, const codeview_reftype* fieldlist, int maxdlen); 56 | int countFields(const codeview_reftype* fieldlist); 57 | int countNestedTypes(const codeview_reftype* fieldlist, int type); 58 | 59 | int addAggregate(codeview_type* dtype, bool clss, int n_element, int fieldlist, int property, 60 | int derived, int vshape, int structlen, const char*name, const char*uniquename); 61 | int addClass(codeview_type* dtype, int n_element, int fieldlist, int property, 62 | int derived, int vshape, int structlen, const char*name, const char*uniquename = 0); 63 | int addStruct(codeview_type* dtype, int n_element, int fieldlist, int property, 64 | int derived, int vshape, int structlen, const char*name, const char*uniquename = 0); 65 | int addEnum(codeview_type* dtype, int count, int fieldlist, int property, 66 | int type, const char*name); 67 | 68 | int addPointerType(codeview_type* dtype, int type, int attr = 0x800A); 69 | int addPointerType(unsigned char* dtype, int type, int attr = 0x800A); 70 | 71 | int addFieldMember(codeview_fieldtype* dfieldtype, int attr, int offset, int type, const char* name); 72 | int addFieldStaticMember(codeview_fieldtype* dfieldtype, int attr, int type, const char* name); 73 | int addFieldNestedType(codeview_fieldtype* dfieldtype, int type, const char* name); 74 | int addFieldEnumerate(codeview_fieldtype* dfieldtype, const char* name, int val); 75 | 76 | void checkUserTypeAlloc(int size = 1000, int add = 10000); 77 | void checkGlobalTypeAlloc(int size, int add = 1000); 78 | void checkUdtSymbolAlloc(int size, int add = 10000); 79 | void checkDWARFTypeAlloc(int size, int add = 10000); 80 | void writeUserTypeLen(codeview_type* type, int len); 81 | 82 | const codeview_type* getTypeData(int type); 83 | const codeview_type* getUserTypeData(int type); 84 | const codeview_type* getConvertedTypeData(int type); 85 | const codeview_type* findCompleteClassType(const codeview_type* cvtype, int* ptype = 0); 86 | 87 | int findMemberFunctionType(codeview_symbol* lastGProcSym, int thisPtrType); 88 | int createEmptyFieldListType(); 89 | 90 | int fixProperty(int type, int prop, int fieldType); 91 | bool derivesFromObject(const codeview_type* cvtype); 92 | bool isCppInterface(const codeview_type* cvtype); 93 | bool isClassType(int type); 94 | 95 | int sizeofClassType(const codeview_type* cvtype); 96 | int sizeofBasicType(int type); 97 | int sizeofType(int type); 98 | 99 | // to be used when writing new type only to avoid double translation 100 | int translateType(int type); 101 | int getBaseClass(const codeview_type* cvtype); 102 | int countBaseClasses(const codeview_type* cvtype); 103 | 104 | bool nameOfBasicType(int type, char* name, int maxlen); 105 | bool nameOfType(int type, char* name, int maxlen); 106 | bool nameOfDynamicArray(int indexType, int elemType, char* name, int maxlen); 107 | bool nameOfAssocArray(int indexType, int elemType, char* name, int maxlen); 108 | bool nameOfDelegate(int thisType, int funcType, char* name, int maxlen); 109 | bool nameOfOEMType(codeview_oem_type* oem, char* name, int maxlen); 110 | bool nameOfModifierType(int type, int mod, char* name, int maxlen); 111 | 112 | int numeric_leaf(int* value, const void* leaf); 113 | int copy_leaf(unsigned char* dp, int& dpos, const unsigned char* p, int& pos); 114 | 115 | const char* appendDynamicArray(int indexType, int elemType); 116 | const char* appendDelegate(int thisType, int funcType); 117 | int appendAssocArray2068(codeview_type* dtype, int keyType, int elemType); 118 | int appendAssocArray(codeview_type* dtype, int keyType, int elemType); 119 | int appendObjectType (int object_derived_type, int enumType, const char* classSymbol); 120 | int appendPointerType(int pointedType, int attr); 121 | int appendModifierType(int type, int attr); 122 | int appendTypedef(int type, const char* name, bool saveTranslation = true); 123 | int appendComplex(int cplxtype, int basetype, int elemsize, const char* name); 124 | void appendTypedefs(); 125 | int appendEnumerator(const char* typeName, const char* enumName, int enumValue, int prop); 126 | int appendClassTypeEnum(const codeview_type* fieldlist, int type, const char* name); 127 | void appendStackVar(const char* name, int type, Location& loc, Location& cfa); 128 | void appendGlobalVar(const char* name, int type, int seg, int offset); 129 | bool appendEndArg(); 130 | void appendEnd(); 131 | void appendLexicalBlock(DWARF_InfoData& id, unsigned int proclo); 132 | 133 | bool hasClassTypeEnum(const codeview_type* fieldlist); 134 | bool insertClassTypeEnums(); 135 | int insertBaseClass(const codeview_type* fieldlist, int type); 136 | 137 | bool initGlobalTypes(); 138 | bool initGlobalSymbols(); 139 | 140 | bool addTypes(); 141 | bool addSrcLines(); 142 | bool addSrcLines14(); 143 | bool addPublics(); 144 | 145 | codeview_symbol* findUdtSymbol(int type); 146 | codeview_symbol* findUdtSymbol(const char* name); 147 | bool addUdtSymbol(int type, const char* name); 148 | void ensureUDT(int type, const codeview_type* cvtype); 149 | 150 | // returns new destSize 151 | int copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int destSize); 152 | 153 | bool writeSymbols(mspdb::Mod* mod, DWORD* data, int databytes, int prefix, bool addGlobals); 154 | bool addSymbols(mspdb::Mod* mod, BYTE* symbols, int cb, bool addGlobals); 155 | bool addSymbols(int iMod, BYTE* symbols, int cb, bool addGlobals); 156 | bool addSymbols(); 157 | 158 | bool markSrcLineInBitmap(int segIndex, int adr); 159 | bool createSrcLineBitmap(); 160 | int getNextSrcLine(int seg, unsigned int off); 161 | 162 | bool writeImage(const TCHAR* opath, PEImage& exeImage); 163 | 164 | mspdb::Mod* globalMod(); 165 | 166 | // DWARF 167 | bool createDWARFModules(); 168 | bool addDWARFTypes(); 169 | bool addDWARFLines(); 170 | bool addDWARFPublics(); 171 | bool writeDWARFImage(const TCHAR* opath); 172 | DWARF_InfoData* findEntryByPtr(byte* entryPtr) const; 173 | 174 | // Helper to just print the DWARF tree we've built for debugging purposes. 175 | void dumpDwarfTree() const; 176 | 177 | bool addDWARFSectionContrib(mspdb::Mod* mod, unsigned long pclo, unsigned long pchi); 178 | bool addDWARFProc(DWARF_InfoData& id, const std::vector &ranges, DIECursor cursor); 179 | void formatFullyQualifiedName(const DWARF_InfoData* node, char* buf, size_t cbBuf) const; 180 | 181 | int addDWARFStructure(DWARF_InfoData& id, DIECursor cursor); 182 | int addDWARFFields(DWARF_InfoData& structid, DIECursor& cursor, int off, int flStart); 183 | int addDWARFArray(DWARF_InfoData& arrayid, const DIECursor& cursor); 184 | int addDWARFBasicType(const char*name, int encoding, int byte_size); 185 | int addDWARFEnum(DWARF_InfoData& enumid, DIECursor cursor); 186 | int getTypeByDWARFPtr(byte* typePtr); 187 | int findTypeIdByPtr(byte* typePtr) const; 188 | int getDWARFTypeSize(const DIECursor& parent, byte* ptr); 189 | void getDWARFArrayBounds(DIECursor cursor, 190 | int& basetype, int& lowerBound, int& upperBound); 191 | void getDWARFSubrangeInfo(DWARF_InfoData& subrangeid, const DIECursor& parent, 192 | int& basetype, int& lowerBound, int& upperBound); 193 | int getDWARFBasicType(int encoding, int byte_size); 194 | 195 | void build_cfi_index(); 196 | bool mapTypes(); 197 | bool createTypes(); 198 | 199 | // private: 200 | BYTE* libraries; 201 | 202 | PEImage& img; 203 | // imgDbg - debug information, points to debug information in 'img' or a separate image 204 | const PEImage* imgDbg; 205 | CFIIndex* cfi_index; 206 | 207 | mspdb::PDB* pdb; 208 | mspdb::DBI *dbi; 209 | mspdb::TPI *tpi; 210 | mspdb::TPI *ipi; 211 | 212 | mspdb::Mod** modules; 213 | mspdb::Mod* globmod; 214 | int countEntries; 215 | 216 | OMFSignatureRSDS* rsds; 217 | int rsdsLen; 218 | 219 | OMFSegMap* segMap; 220 | OMFSegMapDesc* segMapDesc; 221 | int* segFrame2Index; 222 | 223 | // CV-only 224 | OMFGlobalTypes* globalTypeHeader; 225 | 226 | unsigned char* globalTypes; 227 | int cbGlobalTypes; 228 | int allocGlobalTypes; 229 | 230 | unsigned char* userTypes; 231 | int* pointerTypes; 232 | int cbUserTypes; 233 | int allocUserTypes; 234 | 235 | unsigned char* globalSymbols; 236 | int cbGlobalSymbols; 237 | 238 | unsigned char* staticSymbols; 239 | int cbStaticSymbols; 240 | 241 | unsigned char* udtSymbols; 242 | int cbUdtSymbols; 243 | int allocUdtSymbols; 244 | 245 | unsigned char* dwarfTypes; 246 | int cbDwarfTypes; 247 | int allocDwarfTypes; 248 | 249 | static constexpr int BASE_USER_TYPE = 0x1000; 250 | 251 | int nextUserType = BASE_USER_TYPE; 252 | int nextDwarfType = BASE_USER_TYPE; 253 | int objectType; 254 | 255 | int emptyFieldListType; 256 | int classEnumType; 257 | int ifaceEnumType; 258 | int cppIfaceEnumType; 259 | int structEnumType; 260 | 261 | int classBaseType; 262 | int ifaceBaseType; 263 | int cppIfaceBaseType; 264 | int structBaseType; 265 | 266 | // D named types 267 | int typedefs[20]; 268 | int translatedTypedefs[20]; 269 | int cntTypedefs; 270 | 271 | bool addClassTypeEnum; 272 | bool addStringViewHelper; 273 | bool addObjectViewHelper; 274 | bool methodListToOneMethod; 275 | bool removeMethodLists; 276 | bool useGlobalMod; 277 | bool thisIsNotRef; 278 | bool v3; 279 | DebugLevel debug; 280 | const char* lastError; 281 | 282 | int srcLineSections; 283 | char** srcLineStart; // array of bitmaps per segment, indicating whether src line start is available for corresponding address 284 | 285 | double Dversion; 286 | 287 | // DWARF fields. 288 | 289 | int codeSegOff; 290 | 291 | // Lookup table for type IDs based on the DWARF_InfoData::entryPtr 292 | std::unordered_map mapEntryPtrToTypeID; 293 | 294 | // Lookup table for entries based on the DWARF_InfoData::entryPtr 295 | std::unordered_map mapEntryPtrToEntry; 296 | 297 | // A multimap keyed on entry name. Since this is not unique, we use a multimap. 298 | std::multimap mapEntryNameToEntries; 299 | 300 | // Head of list of DWARF DIE nodes. 301 | DWARF_InfoData* dwarfHead = nullptr; 302 | 303 | // Default lower bound for the current compilation unit. This depends on 304 | // the language of the current unit. 305 | unsigned currentDefaultLowerBound; 306 | }; 307 | 308 | #endif //__CV2PDB_H__ 309 | -------------------------------------------------------------------------------- /src/cv2pdb.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cv2pdb", "cv2pdb.vcproj", "{5E2BD27D-446A-4C99-9829-135F7C000D90}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dviewhelper", "dviewhelper\dviewhelper.vcproj", "{E4424774-A7A0-4502-8626-2723904D70EA}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7F4A9B6A-05A2-45D0-AFC3-3754B7FB77B9}" 9 | ProjectSection(SolutionItems) = preProject 10 | ..\autoexp.expand = ..\autoexp.expand 11 | ..\autoexp.visualizer = ..\autoexp.visualizer 12 | ..\CHANGES = ..\CHANGES 13 | ..\FEATURES = ..\FEATURES 14 | ..\INSTALL = ..\INSTALL 15 | ..\LICENSE = ..\LICENSE 16 | ..\Makefile = ..\Makefile 17 | ..\README = ..\README 18 | ..\TODO = ..\TODO 19 | ..\VERSION = ..\VERSION 20 | EndProjectSection 21 | EndProject 22 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cvtest", "..\test\cvtest.vcproj", "{CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}" 23 | ProjectSection(ProjectDependencies) = postProject 24 | {5E2BD27D-446A-4C99-9829-135F7C000D90} = {5E2BD27D-446A-4C99-9829-135F7C000D90} 25 | EndProjectSection 26 | EndProject 27 | Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "test", "..\test\test.visualdproj", "{370E7494-D0CB-450F-B74A-4CEEDB19FBAE}" 28 | EndProject 29 | Project("{8BC9CEB9-8B4A-11D0-8D11-00A0C91BC942}") = "test64.exe", "..\bin\Debug GDCWin32\test64.exe", "{022545C9-DE2E-44F0-B87C-74CEAC3202F6}" 30 | EndProject 31 | Global 32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 33 | Debug GDC|Win32 = Debug GDC|Win32 34 | Debug GDC|x64 = Debug GDC|x64 35 | Debug|Win32 = Debug|Win32 36 | Debug|x64 = Debug|x64 37 | Release|Win32 = Release|Win32 38 | Release|x64 = Release|x64 39 | EndGlobalSection 40 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 41 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug GDC|Win32.ActiveCfg = Debug|Win32 42 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug GDC|Win32.Build.0 = Debug|Win32 43 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug GDC|x64.ActiveCfg = Debug|Win32 44 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|Win32.ActiveCfg = Debug|Win32 45 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|Win32.Build.0 = Debug|Win32 46 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|x64.ActiveCfg = Debug|Win32 47 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|Win32.ActiveCfg = Release|Win32 48 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|Win32.Build.0 = Release|Win32 49 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|x64.ActiveCfg = Release|Win32 50 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug GDC|Win32.ActiveCfg = Debug|Win32 51 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug GDC|Win32.Build.0 = Debug|Win32 52 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug GDC|x64.ActiveCfg = Debug|Win32 53 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug|Win32.ActiveCfg = Debug|Win32 54 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug|Win32.Build.0 = Debug|Win32 55 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug|x64.ActiveCfg = Debug|Win32 56 | {E4424774-A7A0-4502-8626-2723904D70EA}.Release|Win32.ActiveCfg = Release|Win32 57 | {E4424774-A7A0-4502-8626-2723904D70EA}.Release|Win32.Build.0 = Release|Win32 58 | {E4424774-A7A0-4502-8626-2723904D70EA}.Release|x64.ActiveCfg = Release|Win32 59 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug GDC|Win32.ActiveCfg = Debug|Win32 60 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug GDC|Win32.Build.0 = Debug|Win32 61 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug GDC|x64.ActiveCfg = Debug|Win32 62 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug|Win32.ActiveCfg = Debug|Win32 63 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug|Win32.Build.0 = Debug|Win32 64 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug|x64.ActiveCfg = Debug|Win32 65 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Release|Win32.ActiveCfg = Release|Win32 66 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Release|Win32.Build.0 = Release|Win32 67 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Release|x64.ActiveCfg = Release|Win32 68 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug GDC|Win32.ActiveCfg = Debug GDC|Win32 69 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug GDC|Win32.Build.0 = Debug GDC|Win32 70 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug GDC|x64.ActiveCfg = Debug GDC|x64 71 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug GDC|x64.Build.0 = Debug GDC|x64 72 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug|Win32.ActiveCfg = Debug|Win32 73 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug|Win32.Build.0 = Debug|Win32 74 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug|x64.ActiveCfg = Debug|x64 75 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug|x64.Build.0 = Debug|x64 76 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Release|Win32.ActiveCfg = Release|Win32 77 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Release|Win32.Build.0 = Release|Win32 78 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Release|x64.ActiveCfg = Release|x64 79 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Release|x64.Build.0 = Release|x64 80 | {022545C9-DE2E-44F0-B87C-74CEAC3202F6}.Debug GDC|Win32.ActiveCfg = Debug 81 | {022545C9-DE2E-44F0-B87C-74CEAC3202F6}.Debug GDC|x64.ActiveCfg = Debug 82 | {022545C9-DE2E-44F0-B87C-74CEAC3202F6}.Debug|Win32.ActiveCfg = Debug 83 | {022545C9-DE2E-44F0-B87C-74CEAC3202F6}.Debug|x64.ActiveCfg = Debug 84 | {022545C9-DE2E-44F0-B87C-74CEAC3202F6}.Release|Win32.ActiveCfg = Debug 85 | {022545C9-DE2E-44F0-B87C-74CEAC3202F6}.Release|x64.ActiveCfg = Debug 86 | EndGlobalSection 87 | GlobalSection(SolutionProperties) = preSolution 88 | HideSolutionNode = FALSE 89 | EndGlobalSection 90 | EndGlobal 91 | -------------------------------------------------------------------------------- /src/cv2pdb.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 55 | 58 | 61 | 64 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 103 | 106 | 109 | 112 | 115 | 118 | 132 | 135 | 138 | 141 | 151 | 154 | 157 | 160 | 163 | 166 | 169 | 172 | 173 | 174 | 175 | 176 | 177 | 182 | 185 | 186 | 189 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 205 | 206 | 209 | 210 | 213 | 214 | 217 | 218 | 221 | 222 | 225 | 226 | 229 | 230 | 233 | 234 | 237 | 238 | 241 | 242 | 245 | 246 | 249 | 250 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | -------------------------------------------------------------------------------- /src/cv2pdb.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | Source Files 15 | 16 | 17 | Source Files 18 | 19 | 20 | Source Files 21 | 22 | 23 | Source Files 24 | 25 | 26 | Source Files 27 | 28 | 29 | Source Files 30 | 31 | 32 | Source Files 33 | 34 | 35 | Source Files 36 | 37 | 38 | Source Files 39 | 40 | 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | Source Files 71 | 72 | 73 | Source Files 74 | 75 | 76 | 77 | 78 | Source Files 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/cv2pdb_vs12.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28407.52 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7F4A9B6A-05A2-45D0-AFC3-3754B7FB77B9}" 7 | ProjectSection(SolutionItems) = preProject 8 | ..\autoexp.expand = ..\autoexp.expand 9 | ..\autoexp.visualizer = ..\autoexp.visualizer 10 | ..\CHANGES = ..\CHANGES 11 | ..\FEATURES = ..\FEATURES 12 | ..\INSTALL = ..\INSTALL 13 | ..\LICENSE = ..\LICENSE 14 | ..\Makefile = ..\Makefile 15 | ..\README.MD = ..\README.MD 16 | ..\TODO = ..\TODO 17 | ..\VERSION = ..\VERSION 18 | EndProjectSection 19 | EndProject 20 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cv2pdb", "cv2pdb.vcxproj", "{5E2BD27D-446A-4C99-9829-135F7C000D90}" 21 | EndProject 22 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dviewhelper", "dviewhelper\dviewhelper.vcxproj", "{E4424774-A7A0-4502-8626-2723904D70EA}" 23 | EndProject 24 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cvtest", "..\test\cvtest.vcxproj", "{CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}" 25 | EndProject 26 | Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "test", "..\test\test.visualdproj", "{370E7494-D0CB-450F-B74A-4CEEDB19FBAE}" 27 | EndProject 28 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dumplines", "dumplines.vcxproj", "{6434537D-446A-4C99-9829-135F7C000D90}" 29 | EndProject 30 | Global 31 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 32 | Debug GDC|Win32 = Debug GDC|Win32 33 | Debug GDC|x64 = Debug GDC|x64 34 | Debug|Win32 = Debug|Win32 35 | Debug|x64 = Debug|x64 36 | Release|Win32 = Release|Win32 37 | Release|x64 = Release|x64 38 | Win32 COFF|Win32 = Win32 COFF|Win32 39 | Win32 COFF|x64 = Win32 COFF|x64 40 | EndGlobalSection 41 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 42 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug GDC|Win32.ActiveCfg = Debug|Win32 43 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug GDC|Win32.Build.0 = Debug|Win32 44 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug GDC|x64.ActiveCfg = Debug|Win32 45 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|Win32.ActiveCfg = Debug|Win32 46 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|Win32.Build.0 = Debug|Win32 47 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|x64.ActiveCfg = Debug|x64 48 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|x64.Build.0 = Debug|x64 49 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|Win32.ActiveCfg = Release|Win32 50 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|Win32.Build.0 = Release|Win32 51 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|x64.ActiveCfg = Release|x64 52 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|x64.Build.0 = Release|x64 53 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Win32 COFF|Win32.ActiveCfg = Debug|Win32 54 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Win32 COFF|Win32.Build.0 = Debug|Win32 55 | {5E2BD27D-446A-4C99-9829-135F7C000D90}.Win32 COFF|x64.ActiveCfg = Release|Win32 56 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug GDC|Win32.ActiveCfg = Debug|Win32 57 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug GDC|Win32.Build.0 = Debug|Win32 58 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug GDC|x64.ActiveCfg = Debug|Win32 59 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug|Win32.ActiveCfg = Debug|Win32 60 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug|Win32.Build.0 = Debug|Win32 61 | {E4424774-A7A0-4502-8626-2723904D70EA}.Debug|x64.ActiveCfg = Debug|Win32 62 | {E4424774-A7A0-4502-8626-2723904D70EA}.Release|Win32.ActiveCfg = Release|Win32 63 | {E4424774-A7A0-4502-8626-2723904D70EA}.Release|Win32.Build.0 = Release|Win32 64 | {E4424774-A7A0-4502-8626-2723904D70EA}.Release|x64.ActiveCfg = Release|Win32 65 | {E4424774-A7A0-4502-8626-2723904D70EA}.Win32 COFF|Win32.ActiveCfg = Debug|Win32 66 | {E4424774-A7A0-4502-8626-2723904D70EA}.Win32 COFF|Win32.Build.0 = Debug|Win32 67 | {E4424774-A7A0-4502-8626-2723904D70EA}.Win32 COFF|x64.ActiveCfg = Release|Win32 68 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug GDC|Win32.ActiveCfg = Debug|Win32 69 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug GDC|Win32.Build.0 = Debug|Win32 70 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug GDC|x64.ActiveCfg = Debug|Win32 71 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug|Win32.ActiveCfg = Debug|Win32 72 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug|Win32.Build.0 = Debug|Win32 73 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Debug|x64.ActiveCfg = Debug|Win32 74 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Release|Win32.ActiveCfg = Release|Win32 75 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Release|Win32.Build.0 = Release|Win32 76 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Release|x64.ActiveCfg = Release|Win32 77 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Win32 COFF|Win32.ActiveCfg = Debug|Win32 78 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Win32 COFF|Win32.Build.0 = Debug|Win32 79 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF}.Win32 COFF|x64.ActiveCfg = Release|Win32 80 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug GDC|Win32.ActiveCfg = Debug GDC|Win32 81 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug GDC|Win32.Build.0 = Debug GDC|Win32 82 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug GDC|x64.ActiveCfg = Debug GDC|x64 83 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug GDC|x64.Build.0 = Debug GDC|x64 84 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug|Win32.ActiveCfg = Debug|Win32 85 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug|Win32.Build.0 = Debug|Win32 86 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug|x64.ActiveCfg = Debug|x64 87 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Debug|x64.Build.0 = Debug|x64 88 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Release|Win32.ActiveCfg = Release|Win32 89 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Release|Win32.Build.0 = Release|Win32 90 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Release|x64.ActiveCfg = Release|x64 91 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Release|x64.Build.0 = Release|x64 92 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Win32 COFF|Win32.ActiveCfg = Win32 COFF|Win32 93 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Win32 COFF|Win32.Build.0 = Win32 COFF|Win32 94 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Win32 COFF|x64.ActiveCfg = Win32 COFF|x64 95 | {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Win32 COFF|x64.Build.0 = Win32 COFF|x64 96 | {6434537D-446A-4C99-9829-135F7C000D90}.Debug GDC|Win32.ActiveCfg = Debug|Win32 97 | {6434537D-446A-4C99-9829-135F7C000D90}.Debug GDC|Win32.Build.0 = Debug|Win32 98 | {6434537D-446A-4C99-9829-135F7C000D90}.Debug GDC|x64.ActiveCfg = Debug|Win32 99 | {6434537D-446A-4C99-9829-135F7C000D90}.Debug|Win32.ActiveCfg = Debug|Win32 100 | {6434537D-446A-4C99-9829-135F7C000D90}.Debug|Win32.Build.0 = Debug|Win32 101 | {6434537D-446A-4C99-9829-135F7C000D90}.Debug|x64.ActiveCfg = Debug|Win32 102 | {6434537D-446A-4C99-9829-135F7C000D90}.Release|Win32.ActiveCfg = Release|Win32 103 | {6434537D-446A-4C99-9829-135F7C000D90}.Release|Win32.Build.0 = Release|Win32 104 | {6434537D-446A-4C99-9829-135F7C000D90}.Release|x64.ActiveCfg = Release|Win32 105 | {6434537D-446A-4C99-9829-135F7C000D90}.Win32 COFF|Win32.ActiveCfg = Release|Win32 106 | {6434537D-446A-4C99-9829-135F7C000D90}.Win32 COFF|Win32.Build.0 = Release|Win32 107 | {6434537D-446A-4C99-9829-135F7C000D90}.Win32 COFF|x64.ActiveCfg = Release|Win32 108 | EndGlobalSection 109 | GlobalSection(SolutionProperties) = preSolution 110 | HideSolutionNode = FALSE 111 | EndGlobalSection 112 | GlobalSection(ExtensibilityGlobals) = postSolution 113 | SolutionGuid = {F1D69C48-7243-4479-A9CE-1FACCFA1D4EA} 114 | EndGlobalSection 115 | EndGlobal 116 | -------------------------------------------------------------------------------- /src/cvt80to64.asm: -------------------------------------------------------------------------------- 1 | _TEXT SEGMENT 2 | 3 | PUBLIC cvt80to64 4 | 5 | cvt80to64 PROC 6 | fld tbyte ptr [rcx] 7 | fstp qword ptr [rdx] 8 | ret 0 9 | cvt80to64 ENDP 10 | 11 | _TEXT ENDS 12 | END -------------------------------------------------------------------------------- /src/cvutil.cpp: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #include "cvutil.h" 8 | 9 | bool isStruct(const codeview_type* cvtype) 10 | { 11 | switch (cvtype->generic.id) 12 | { 13 | case LF_STRUCTURE_V1: 14 | case LF_CLASS_V1: 15 | case LF_STRUCTURE_V2: 16 | case LF_CLASS_V2: 17 | case LF_STRUCTURE_V3: 18 | case LF_CLASS_V3: 19 | return true; 20 | } 21 | return false; 22 | } 23 | 24 | bool isClass(const codeview_type* cvtype) 25 | { 26 | switch (cvtype->generic.id) 27 | { 28 | case LF_CLASS_V1: 29 | case LF_CLASS_V2: 30 | case LF_CLASS_V3: 31 | return true; 32 | } 33 | return false; 34 | } 35 | 36 | int getStructProperty(const codeview_type* cvtype) 37 | { 38 | switch (cvtype->generic.id) 39 | { 40 | case LF_STRUCTURE_V1: 41 | case LF_CLASS_V1: 42 | return cvtype->struct_v1.property; 43 | case LF_STRUCTURE_V2: 44 | case LF_CLASS_V2: 45 | return cvtype->struct_v2.property; 46 | case LF_STRUCTURE_V3: 47 | case LF_CLASS_V3: 48 | return cvtype->struct_v3.property; 49 | } 50 | return 0; 51 | } 52 | 53 | int getStructFieldlist(const codeview_type* cvtype) 54 | { 55 | switch (cvtype->generic.id) 56 | { 57 | case LF_STRUCTURE_V1: 58 | case LF_CLASS_V1: 59 | return cvtype->struct_v1.fieldlist; 60 | case LF_STRUCTURE_V2: 61 | case LF_CLASS_V2: 62 | return cvtype->struct_v2.fieldlist; 63 | case LF_STRUCTURE_V3: 64 | case LF_CLASS_V3: 65 | return cvtype->struct_v3.fieldlist; 66 | } 67 | return 0; 68 | } 69 | 70 | const BYTE* getStructName(const codeview_type* cvtype, bool &cstr) 71 | { 72 | int value, leaf_len; 73 | switch (cvtype->generic.id) 74 | { 75 | case LF_STRUCTURE_V1: 76 | case LF_CLASS_V1: 77 | cstr = false; 78 | leaf_len = numeric_leaf(&value, &cvtype->struct_v1.structlen); 79 | return (const BYTE*) &cvtype->struct_v1.structlen + leaf_len; 80 | case LF_STRUCTURE_V2: 81 | case LF_CLASS_V2: 82 | cstr = false; 83 | leaf_len = numeric_leaf(&value, &cvtype->struct_v2.structlen); 84 | return (const BYTE*) &cvtype->struct_v2.structlen + leaf_len; 85 | case LF_STRUCTURE_V3: 86 | case LF_CLASS_V3: 87 | cstr = true; 88 | leaf_len = numeric_leaf(&value, &cvtype->struct_v3.structlen); 89 | return (const BYTE*) &cvtype->struct_v3.structlen + leaf_len; 90 | } 91 | return 0; 92 | } 93 | 94 | bool cmpStructName(const codeview_type* cvtype, const BYTE* name, bool cstr) 95 | { 96 | bool cstr2; 97 | const BYTE* name2 = getStructName(cvtype, cstr2); 98 | if(!name || !name2) 99 | return name == name2; 100 | return dstrcmp(name, cstr, name2, cstr2); 101 | } 102 | 103 | bool isCompleteStruct(const codeview_type* type, const BYTE* name, bool cstr) 104 | { 105 | return isStruct(type) 106 | && !(getStructProperty(type) & kPropIncomplete) 107 | && cmpStructName(type, name, cstr); 108 | } 109 | 110 | int numeric_leaf(int* value, const void* leaf) 111 | { 112 | unsigned short int type = *(const unsigned short int*) leaf; 113 | leaf = (const unsigned short int*) leaf + 1; 114 | int length = 2; 115 | 116 | *value = 0; 117 | switch (type) 118 | { 119 | case LF_CHAR: 120 | length += 1; 121 | *value = *(const char*)leaf; 122 | break; 123 | 124 | case LF_SHORT: 125 | length += 2; 126 | *value = *(const short*)leaf; 127 | break; 128 | 129 | case LF_USHORT: 130 | length += 2; 131 | *value = *(const unsigned short*)leaf; 132 | break; 133 | 134 | case LF_LONG: 135 | case LF_ULONG: 136 | length += 4; 137 | *value = *(const int*)leaf; 138 | break; 139 | 140 | case LF_COMPLEX64: 141 | case LF_QUADWORD: 142 | case LF_UQUADWORD: 143 | case LF_REAL64: 144 | length += 8; 145 | break; 146 | 147 | case LF_COMPLEX32: 148 | case LF_REAL32: 149 | length += 4; 150 | break; 151 | 152 | case LF_REAL48: 153 | length += 6; 154 | break; 155 | 156 | case LF_COMPLEX80: 157 | case LF_REAL80: 158 | length += 10; 159 | break; 160 | 161 | case LF_COMPLEX128: 162 | case LF_REAL128: 163 | length += 16; 164 | break; 165 | 166 | case LF_VARSTRING: 167 | length += 2 + *(const unsigned short*)leaf; 168 | break; 169 | 170 | default: 171 | if (type < LF_NUMERIC) 172 | *value = type; 173 | else 174 | { 175 | length = 0; // error! 176 | } 177 | break; 178 | } 179 | return length; 180 | } 181 | 182 | int write_numeric_leaf(int value, void* leaf) 183 | { 184 | if(value >= 0 && value < LF_NUMERIC) 185 | { 186 | *(unsigned short int*) leaf = (unsigned short) value; 187 | return 2; 188 | } 189 | unsigned short int* type = (unsigned short int*) leaf; 190 | leaf = type + 1; 191 | if (value >= -128 && value <= 127) 192 | { 193 | *type = LF_CHAR; 194 | *(char*) leaf = (char)value; 195 | return 3; 196 | } 197 | if (value >= -32768 && value <= 32767) 198 | { 199 | *type = LF_SHORT; 200 | *(short*) leaf = (short)value; 201 | return 4; 202 | } 203 | if (value >= 0 && value <= 65535) 204 | { 205 | *type = LF_USHORT; 206 | *(unsigned short*) leaf = (unsigned short)value; 207 | return 4; 208 | } 209 | *type = LF_LONG; 210 | *(long*) leaf = (long)value; 211 | return 6; 212 | } 213 | 214 | -------------------------------------------------------------------------------- /src/cvutil.h: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #ifndef __CVUTIL_H__ 8 | #define __CVUTIL_H__ 9 | 10 | #include "cv2pdb.h" 11 | #include "symutil.h" 12 | 13 | #define OBJECT_SYMBOL "object.Object" 14 | #define IFACE_SYMBOL "DInterface" 15 | #define CPPIFACE_SYMBOL "CppInterface" 16 | 17 | #define P_OBJECT_SYMBOL ((const BYTE*)("\x0d" OBJECT_SYMBOL)) 18 | 19 | #define CLASSTYPEENUM_TYPE "__ClassType" 20 | #define CLASSTYPEENUM_NAME "__classtype" 21 | 22 | enum 23 | { 24 | kClassTypeObject = 1, 25 | kClassTypeIface = 2, 26 | kClassTypeCppIface = 3, 27 | kClassTypeStruct = 4 28 | }; 29 | 30 | // class properties (also apply to struct,union and enum) 31 | static const int kPropNone = 0x00; 32 | static const int kPropPacked = 0x01; 33 | static const int kPropHasCtorDtor = 0x02; 34 | static const int kPropHasOverOps = 0x04; 35 | static const int kPropIsNested = 0x08; 36 | static const int kPropHasNested = 0x10; 37 | static const int kPropHasOverAsgn = 0x20; 38 | static const int kPropHasCasting = 0x40; 39 | static const int kPropIncomplete = 0x80; 40 | static const int kPropScoped = 0x100; 41 | static const int kPropUniquename = 0x200; 42 | 43 | bool isStruct(const codeview_type* cvtype); 44 | bool isClass(const codeview_type* cvtype); 45 | int getStructProperty(const codeview_type* cvtype); 46 | int getStructFieldlist(const codeview_type* cvtype); 47 | bool isCompleteStruct(const codeview_type* type, const BYTE* name, bool cstr); 48 | 49 | const BYTE* getStructName(const codeview_type* cvtype, bool &cstr); 50 | bool cmpStructName(const codeview_type* cvtype, const BYTE* name, bool cstr); 51 | 52 | int numeric_leaf(int* value, const void* leaf); 53 | int write_numeric_leaf(int value, void* leaf); 54 | 55 | #endif // __CVUTIL_H__ 56 | -------------------------------------------------------------------------------- /src/dcvinfo.h: -------------------------------------------------------------------------------- 1 | #ifndef __DCVINFO_H__ 2 | #define __DCVINFO_H__ 3 | 4 | // DMD CodeViev extensions 5 | 6 | union codeview_oem_type 7 | { 8 | struct 9 | { 10 | short int oemid; 11 | short int id; 12 | short int count; 13 | } generic; 14 | 15 | struct 16 | { 17 | short int oemid; // 0x42 for D 18 | short int id; // 1 19 | short int count; // 2 20 | short unsigned int index_type; 21 | short unsigned int elem_type; 22 | } d_dyn_array; 23 | 24 | struct 25 | { 26 | short int oemid; // 0x42 for D 27 | short int id; // 2 28 | short int count; // 2 29 | short unsigned int key_type; 30 | short unsigned int elem_type; 31 | } d_assoc_array; 32 | 33 | struct 34 | { 35 | short int oemid; // 0x42 for D 36 | short int id; // 3 37 | short int count; // 2 38 | short unsigned int this_type; 39 | short unsigned int func_type; 40 | } d_delegate; 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/demangle.cpp: -------------------------------------------------------------------------------- 1 | // adopted from demangle.d distributed with DMD 2 | 3 | /**** 4 | * Demangle D mangled names. 5 | * Macros: 6 | * WIKI = Phobos/StdDemangle 7 | */ 8 | 9 | /* Authors: 10 | * Walter Bright, Digital Mars, www.digitalmars.com 11 | * Thomas Kuehne 12 | * Frits van Bommel 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "symutil.h" 20 | 21 | #ifdef _M_X64 22 | extern "C" void cvt80to64(void * in, long double * out); 23 | #elif _M_ARM64 24 | void cvt80to64(void * in, long double * out) { 25 | printf("cvt80to64 is only supported on x64 processors."); 26 | exit(1); 27 | } 28 | #endif 29 | 30 | #define USE_STDSTRING 1 31 | 32 | #if USE_STDSTRING 33 | typedef std::string string; //using namespace std; 34 | #else 35 | static const int maxLen = 4096; 36 | 37 | struct stringpool 38 | { 39 | stringpool() : _first(0) {} 40 | 41 | char* get() 42 | { 43 | if(!_first) 44 | return new char[maxLen]; 45 | char* p = _first; 46 | _first = *(char**) _first; 47 | return p; 48 | } 49 | void put(char* p) 50 | { 51 | *(char**)p = _first; 52 | _first = p; 53 | } 54 | 55 | char* _first; 56 | }; 57 | stringpool pool; 58 | 59 | #define string _string // fool debugger to not use visualizers for std::string 60 | 61 | struct string 62 | { 63 | string() : _p(0), _len(0), _const(false) { _p = pool.get(); } 64 | //string(const char* p) : _cp(p), _len(strlen(p)), _const(true) {} 65 | //string(const string& s) : _p(s.p), _len(s._len), _const(true) {} 66 | string(const char* p, size_t len) : _cp(p), _len(len), _const(true) {} 67 | template string(const char (&p)[N]) : _cp(p), _len(N-1), _const(true) {} 68 | ~string() { if(!_const) pool.put(_p); } 69 | 70 | size_t length() const { return _len; } 71 | 72 | char operator[] (size_t idx) const 73 | { 74 | return _p[idx]; 75 | } 76 | string substr(size_t pos, size_t len) const 77 | { 78 | return string(_p + pos, len); 79 | } 80 | 81 | template string operator+(const char (&p)[N]) 82 | { 83 | assert(!_const); 84 | assert(_len + N-1 < maxLen); 85 | 86 | memcpy(_p + _len, p, N-1); 87 | return string(_p, _len + N-1); 88 | } 89 | string operator+(string s) 90 | { 91 | assert(!_const); 92 | assert(_len + s._len < maxLen); 93 | 94 | memcpy(_p + _len, s._p, s._len); 95 | return string(_p, _len + s._len); 96 | } 97 | template string operator+=(const char (&p)[N]) 98 | { 99 | assert(!_const); 100 | assert(_len + N-1 < maxLen); 101 | memcpy(_p + _len, p, N-1); 102 | _len += N - 1; 103 | return *this; 104 | } 105 | string operator+=(const string& s) 106 | { 107 | assert(!_const); 108 | assert(_len + s._len < maxLen); 109 | memcpy(_p + _len, s._p, s._len); 110 | _len += s._len; 111 | return *this; 112 | } 113 | string operator+=(char c) 114 | { 115 | assert(!_const); 116 | assert(_len < maxLen); 117 | _p[_len++] = c; 118 | return *this; 119 | } 120 | templatestring operator=(const char (&p)[N]) 121 | { 122 | _len = N-1; 123 | memcpy(_p, p, _len); 124 | _const = true; 125 | return *this; 126 | } 127 | string operator=(const string& s) 128 | { 129 | assert(!_const); 130 | _len = s._len; 131 | memcpy(_p, s._p, _len); 132 | return *this; 133 | } 134 | bool operator==(const string& s) const 135 | { 136 | return _len == s._len && memcmp(_p, s._p, _len) == 0; 137 | } 138 | 139 | const char* c_str() 140 | { 141 | assert(!_const); 142 | assert(_len < maxLen); 143 | _p[_len] = 0; 144 | return _p; 145 | } 146 | 147 | union 148 | { 149 | const char* _cp; 150 | char* _p; 151 | }; 152 | size_t _len; 153 | bool _const; 154 | }; 155 | 156 | template string operator+(const char (&p)[N], string s) 157 | { 158 | assert(!s._const); 159 | assert(s._len + N-1 < maxLen); 160 | memmove(s._p + N - 1, s._p, s._len); 161 | memcpy(s._p, p, N-1); 162 | return string(s._p, s._len + N-1); 163 | } 164 | #endif 165 | 166 | typedef unsigned char ubyte; 167 | typedef long double real; 168 | 169 | #define length length() 170 | 171 | #define size_t_max 0x7FFFFFFFU 172 | 173 | class MangleException 174 | { 175 | public: 176 | virtual ~MangleException() {} 177 | }; 178 | 179 | class Demangle 180 | { 181 | public: 182 | size_t ni; 183 | string name; 184 | 185 | static void error() 186 | { 187 | //writefln("error()"); 188 | throw MangleException(); 189 | } 190 | 191 | static ubyte ascii2hex(char c) 192 | { 193 | if (!isxdigit((ubyte)c)) 194 | error(); 195 | return (ubyte) 196 | ( (c >= 'a') ? c - 'a' + 10 : 197 | (c >= 'A') ? c - 'A' + 10 : c - '0' ); 198 | } 199 | 200 | size_t parseNumber() 201 | { 202 | //writefln("parseNumber() %d", ni); 203 | size_t result = 0; 204 | 205 | while (ni < name.length && isdigit((ubyte)name[ni])) 206 | { 207 | int i = name[ni] - '0'; 208 | if (result > (size_t_max - i) / 10) 209 | error(); 210 | result = result * 10 + i; 211 | ni++; 212 | } 213 | return result; 214 | } 215 | 216 | string parseSymbolName() 217 | { 218 | //writefln("parseSymbolName() %d", ni); 219 | size_t i = parseNumber(); 220 | if (ni + i > name.length) 221 | error(); 222 | string result; 223 | if (i >= 5 && 224 | name[ni] == '_' && 225 | name[ni + 1] == '_' && 226 | name[ni + 2] == 'T') 227 | { 228 | size_t nisave = ni; 229 | bool err = false; 230 | ni += 3; 231 | try 232 | { 233 | result = parseTemplateInstanceName(); 234 | if (ni != nisave + i) 235 | err = true; 236 | } 237 | catch (MangleException me) 238 | { 239 | err = true; 240 | } 241 | ni = nisave; 242 | if (err) 243 | goto L1; 244 | goto L2; 245 | } 246 | L1: 247 | result = name.substr(ni, i); 248 | L2: 249 | ni += i; 250 | return result; 251 | } 252 | 253 | string parseQualifiedName() 254 | { 255 | //writefln("parseQualifiedName() %d", ni); 256 | string result; 257 | 258 | while (ni < name.length && isdigit((ubyte)name[ni])) 259 | { 260 | if (result.length) 261 | result += "."; 262 | result += parseSymbolName(); 263 | } 264 | return result; 265 | } 266 | 267 | string parseType(string identifier = string()) 268 | { 269 | //writefln("parseType() %d", ni); 270 | int isdelegate = 0; 271 | bool hasthisptr = false; /// For function/delegate types: expects a 'this' pointer as last argument 272 | Lagain: 273 | if (ni >= name.length) 274 | error(); 275 | string p; 276 | switch (name[ni++]) 277 | { 278 | case 'v': p = "void"; goto L1; 279 | case 'b': p = "bool"; goto L1; 280 | case 'g': p = "byte"; goto L1; 281 | case 'h': p = "ubyte"; goto L1; 282 | case 's': p = "short"; goto L1; 283 | case 't': p = "ushort"; goto L1; 284 | case 'i': p = "int"; goto L1; 285 | case 'k': p = "uint"; goto L1; 286 | case 'l': p = "long"; goto L1; 287 | case 'm': p = "ulong"; goto L1; 288 | case 'f': p = "float"; goto L1; 289 | case 'd': p = "double"; goto L1; 290 | case 'e': p = "real"; goto L1; 291 | case 'o': p = "ifloat"; goto L1; 292 | case 'p': p = "idouble"; goto L1; 293 | case 'j': p = "ireal"; goto L1; 294 | case 'q': p = "cfloat"; goto L1; 295 | case 'r': p = "cdouble"; goto L1; 296 | case 'c': p = "creal"; goto L1; 297 | case 'a': p = "char"; goto L1; 298 | case 'u': p = "wchar"; goto L1; 299 | case 'w': p = "dchar"; goto L1; 300 | 301 | case 'A': // dynamic array 302 | p = parseType() + "[]"; 303 | goto L1; 304 | 305 | case 'P': // pointer 306 | p = parseType() + "*"; 307 | goto L1; 308 | 309 | case 'G': // static array 310 | { size_t ns = ni; 311 | parseNumber(); 312 | size_t ne = ni; 313 | p = parseType() + "[" + name.substr(ns, ne-ns) + "]"; 314 | goto L1; 315 | } 316 | 317 | case 'H': // associative array 318 | p = parseType(); 319 | p = parseType() + "[" + p + "]"; 320 | goto L1; 321 | 322 | case 'D': // delegate 323 | isdelegate = 1; 324 | goto Lagain; 325 | 326 | case 'M': 327 | hasthisptr = true; 328 | goto Lagain; 329 | 330 | case 'y': 331 | p = "immutable(" + parseType() + ")"; 332 | goto L1; 333 | 334 | case 'x': 335 | p = "const(" + parseType() + ")"; 336 | goto L1; 337 | 338 | case 'O': 339 | p = "shared(" + parseType() + ")"; 340 | goto L1; 341 | 342 | case 'F': // D function 343 | case 'U': // C function 344 | case 'W': // Windows function 345 | case 'V': // Pascal function 346 | case 'R': // C++ function 347 | { 348 | char mc = name[ni - 1]; 349 | string args; 350 | string prop; 351 | while(name[ni] == 'N') 352 | { 353 | switch(name[ni+1]) 354 | { 355 | case 'a': prop += "pure "; break; 356 | case 'b': prop += "nothrow "; break; 357 | case 'c': prop += "ref "; break; 358 | case 'd': prop += "@property "; break; 359 | case 'e': prop += "@trusted "; break; 360 | case 'f': prop += "@safe "; break; 361 | default: 362 | goto no_prop; 363 | } 364 | ni += 2; 365 | } 366 | no_prop: 367 | 368 | while (1) 369 | { 370 | if (ni >= name.length) 371 | error(); 372 | char c = name[ni]; 373 | if (c == 'Z') 374 | break; 375 | if (c == 'X') 376 | { 377 | if (!args.length) error(); 378 | args += " ..."; 379 | break; 380 | } 381 | if (args.length) 382 | args += ", "; 383 | switch (c) 384 | { 385 | case 'J': 386 | args += "out "; 387 | ni++; 388 | goto Ldefault; 389 | 390 | case 'K': 391 | args += "ref "; 392 | ni++; 393 | goto Ldefault; 394 | 395 | case 'L': 396 | args += "lazy "; 397 | ni++; 398 | goto Ldefault; 399 | 400 | default: 401 | Ldefault: 402 | args += parseType(); 403 | continue; 404 | 405 | case 'Y': 406 | args += "..."; 407 | break; 408 | } 409 | break; 410 | } 411 | ni++; 412 | if (!isdelegate && identifier.length) 413 | { 414 | switch (mc) 415 | { 416 | case 'F': p = ""; break; // D function 417 | case 'U': p = "extern (C) "; break; // C function 418 | case 'W': p = "extern (Windows) "; break; // Windows function 419 | case 'V': p = "extern (Pascal) "; break; // Pascal function 420 | default: assert(0); 421 | } 422 | p += parseType() + " " + identifier + "(" + args + ")"; 423 | return prop + p; 424 | } 425 | p = prop + parseType() + 426 | (isdelegate ? string(" delegate(") : string(" function(")) + args + ")"; 427 | isdelegate = 0; 428 | goto L1; 429 | } 430 | 431 | case 'C': p = "class "; goto L2; 432 | case 'S': p = "struct "; goto L2; 433 | case 'E': p = "enum "; goto L2; 434 | case 'T': p = "typedef "; goto L2; 435 | 436 | L2: p += parseQualifiedName(); 437 | goto L1; 438 | 439 | L1: 440 | if (isdelegate) 441 | error(); // 'D' must be followed by function 442 | if (identifier.length) 443 | p += " " + identifier; 444 | return p; 445 | 446 | default: 447 | size_t i = ni - 1; 448 | ni = name.length; 449 | p = name.substr(i, name.length-i); 450 | goto L1; 451 | } 452 | } 453 | 454 | void getReal(string &result) 455 | { 456 | real r; 457 | ubyte rdata[10]; 458 | ubyte *p = rdata; 459 | 460 | if (ni + 10 * 2 > name.length) 461 | error(); 462 | for (size_t i = 0; i < 10; i++) 463 | { 464 | ubyte b; 465 | 466 | b = (ubyte) ((ascii2hex(name[ni + i * 2]) << 4) + ascii2hex(name[ni + i * 2 + 1])); 467 | p[i] = b; 468 | } 469 | // extract 10-byte double from rdata 470 | #ifndef _M_IX86 471 | cvt80to64(rdata, &r); 472 | #else 473 | __asm { 474 | fld TBYTE PTR rdata; 475 | fstp r; 476 | } 477 | #endif 478 | 479 | char num[30]; 480 | sprintf(num, "%g", r); 481 | result += num; // format(r); 482 | ni += 10 * 2; 483 | } 484 | 485 | string parseTemplateInstanceName() 486 | { 487 | string result = parseSymbolName() + "!("; 488 | int nargs = 0; 489 | 490 | while (1) 491 | { 492 | size_t i; 493 | 494 | if (ni >= name.length) 495 | error(); 496 | if (nargs && name[ni] != 'Z') 497 | result += ", "; 498 | nargs++; 499 | switch (name[ni++]) 500 | { 501 | case 'T': 502 | result += parseType(); 503 | continue; 504 | 505 | case 'V': 506 | 507 | result += parseType() + " "; 508 | if (ni >= name.length) 509 | error(); 510 | switch (name[ni++]) 511 | { 512 | case '0': case '1': case '2': case '3': case '4': 513 | case '5': case '6': case '7': case '8': case '9': 514 | i = ni - 1; 515 | while (ni < name.length && isdigit((ubyte)name[ni])) 516 | ni++; 517 | result += name.substr(i, ni - i); 518 | break; 519 | 520 | case 'N': 521 | i = ni; 522 | while (ni < name.length && isdigit((ubyte)name[ni])) 523 | ni++; 524 | if (i == ni) 525 | error(); 526 | result += "-" + name.substr(i, ni - i); 527 | break; 528 | 529 | case 'n': 530 | result += "null"; 531 | break; 532 | 533 | case 'e': 534 | getReal(result); 535 | break; 536 | 537 | case 'c': 538 | getReal(result); 539 | result += '+'; 540 | getReal(result); 541 | result += 'i'; 542 | break; 543 | 544 | case 'a': 545 | case 'w': 546 | case 'd': 547 | { char m = name[ni - 1]; 548 | if (m == 'a') 549 | m = 'c'; 550 | size_t n = parseNumber(); 551 | if (ni >= name.length || name[ni++] != '_' || 552 | ni + n * 2 > name.length) 553 | error(); 554 | result += '"'; 555 | for (i = 0; i < n; i++) 556 | { char c; 557 | 558 | c = (char)((ascii2hex(name[ni + i * 2]) << 4) + 559 | ascii2hex(name[ni + i * 2 + 1])); 560 | result += c; 561 | } 562 | ni += n * 2; 563 | result += '"'; 564 | result += m; 565 | break; 566 | } 567 | 568 | default: 569 | error(); 570 | break; 571 | } 572 | continue; 573 | 574 | case 'S': 575 | result += parseSymbolName(); 576 | continue; 577 | 578 | case 'Z': 579 | break; 580 | 581 | default: 582 | error(); 583 | } 584 | break; 585 | } 586 | result += ")"; 587 | return result; 588 | } 589 | 590 | string demangle(string _name, bool plainName = false) 591 | { 592 | ni = 2; 593 | name = _name; 594 | 595 | if (name.length < 3 || 596 | name[0] != '_' || 597 | name[1] != 'D' || 598 | !isdigit((ubyte)name[2])) 599 | { 600 | goto Lnot; 601 | } 602 | 603 | try 604 | { 605 | string result = parseQualifiedName(); 606 | string typed_result = parseType(result); 607 | while(ni < name.length) 608 | { 609 | // throw away outer type (e.g. for local functions) 610 | result = result + "." + parseQualifiedName(); 611 | typed_result = parseType(result); 612 | } 613 | if (!plainName) 614 | result = typed_result; 615 | 616 | if (ni != name.length) 617 | goto Lnot; 618 | return result; 619 | } 620 | catch (MangleException e) 621 | { 622 | } 623 | 624 | Lnot: 625 | // Not a recognized D mangled name; so return original 626 | return name; 627 | } 628 | 629 | }; 630 | 631 | void unittest() 632 | { 633 | // debug(demangle) printf("demangle.demangle.unittest\n"); 634 | 635 | static string table[][2] = 636 | { 637 | { "_D6object14_moduleTlsCtorUZv15_moduleTlsCtor2MFAPS6object10ModuleInfoiZv", "void object._moduleTlsCtor._moduleTlsCtor2(struct object.ModuleInfo*[], int)"}, 638 | { "_D7dparser3dmd8Template21TemplateTypeParameter13overloadMatchMFC7dparser3dmd8Template17TemplateParameterZi", "int dparser.dmd.Template.TemplateTypeParameter.overloadMatch(class dparser.dmd.Template.TemplateParameter)"}, 639 | { "printf", "printf" }, 640 | { "_foo", "_foo" }, 641 | { "_D88", "_D88" }, // causes exception error, return symbol as is 642 | { "_D4test3fooAa", "char[] test.foo"}, 643 | { "_D8demangle8demangleFAaZAa", "char[] demangle.demangle(char[])" }, 644 | { "_D6object6Object8opEqualsFC6ObjectZi", "int object.Object.opEquals(class Object)" }, 645 | { "_D4test2dgDFiYd", "double delegate(int, ...) test.dg" }, 646 | { "_D4test58__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ9factorialf", "float test.factorial!(double 4.2, char[5] \"hello\"c, void* null).factorial" }, 647 | { "_D4test101__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ9factorialf", "float test.factorial!(double 4.2, cdouble 6.8+3i, char[5] \"hello\"c, void* null).factorial" }, 648 | { "_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi", "int test.bar!(wchar[3] \"abc\"w, dchar[3] \"def\"d).x" }, 649 | { "_D8demangle4testFLC6ObjectLDFLiZiZi", "int demangle.test(lazy class Object, lazy int delegate(lazy int))"}, 650 | { "_D8demangle4testFAiXi", "int demangle.test(int[] ...)"}, 651 | { "_D8demangle4testFLAiXi", "int demangle.test(lazy int[] ...)"} , 652 | }; 653 | 654 | Demangle d; 655 | for(int i = 0; i < sizeof(table)/sizeof(table[0]); i++) 656 | { 657 | string r = d.demangle(table[i][0]); 658 | assert(r == table[i][1]); 659 | // "table entry #" + toString(i) + ": '" + name[0] + "' demangles as '" + r + "' but is expected to be '" + name[1] + "'"); 660 | } 661 | 662 | const char s[] = "_D12intellisen\xd1" "11LibraryInfo14findDe\xeaitionMFKS\x80\x8f\xaf" "0SearchDataZA\x80\x91\x9d\x80\x8a\xbb" "8count\x80\x83\x90MFAyaP\x80\x8f\xaa" "9JSONscopeH\x80\x83\x93S3std4json\x80\x85\x98ValueZb"; 663 | char buf[512]; 664 | dsym2c((const BYTE*) s, sizeof(s) - 1, buf, sizeof(buf)); 665 | } 666 | 667 | bool d_demangle(const char* name, char* demangled, int maxlen, bool plain) 668 | { 669 | #ifdef _DEBUG 670 | static bool once; if(!once) { once = true; unittest(); } 671 | #endif 672 | 673 | Demangle d; 674 | string nm(name, strlen(name)); 675 | string r = d.demangle(nm, plain); 676 | if (r.length == 0) 677 | return false; 678 | strncpy(demangled, r.c_str(), maxlen); 679 | return true; 680 | } 681 | -------------------------------------------------------------------------------- /src/demangle.h: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #ifndef __DEMANGLE_H__ 8 | #define __DEMANGLE_H__ 9 | 10 | bool d_demangle(const char* name, char* demangled, int maxlen, bool plain); 11 | 12 | #endif //__DEMANGLE_H__ -------------------------------------------------------------------------------- /src/dumplines.cpp: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #include "PEImage.h" 8 | #include "cv2pdb.h" 9 | #include "symutil.h" 10 | 11 | #include 12 | 13 | double 14 | #include "../VERSION" 15 | ; 16 | 17 | #ifdef UNICODE 18 | #define T_toupper towupper 19 | #define T_getdcwd _wgetdcwd 20 | #define T_strlen wcslen 21 | #define T_strcpy wcscpy 22 | #define T_strcat wcscat 23 | #define T_strstr wcsstr 24 | #define T_strtod wcstod 25 | #define T_strrchr wcsrchr 26 | #define T_unlink _wremove 27 | #define T_main wmain 28 | #define SARG "%S" 29 | #else 30 | #define T_toupper toupper 31 | #define T_getdcwd _getdcwd 32 | #define T_strlen strlen 33 | #define T_strcpy strcpy 34 | #define T_strcat strcat 35 | #define T_strstr strstr 36 | #define T_strtod strtod 37 | #define T_strrchr strrchr 38 | #define T_unlink unlink 39 | #define T_main main 40 | #define SARG "%s" 41 | #endif 42 | 43 | void fatal(const char *message, ...) 44 | { 45 | va_list argptr; 46 | va_start(argptr, message); 47 | vprintf(message, argptr); 48 | va_end(argptr); 49 | printf("\n"); 50 | exit(1); 51 | } 52 | 53 | void makefullpath(TCHAR* pdbname) 54 | { 55 | TCHAR* pdbstart = pdbname; 56 | TCHAR fullname[260]; 57 | TCHAR* pfullname = fullname; 58 | 59 | int drive = 0; 60 | if (pdbname[0] && pdbname[1] == ':') 61 | { 62 | if (pdbname[2] == '\\' || pdbname[2] == '/') 63 | return; 64 | drive = T_toupper (pdbname[0]); 65 | pdbname += 2; 66 | } 67 | else 68 | { 69 | drive = _getdrive(); 70 | } 71 | 72 | if (*pdbname != '\\' && *pdbname != '/') 73 | { 74 | T_getdcwd(drive, pfullname, sizeof(fullname)/sizeof(fullname[0]) - 2); 75 | pfullname += T_strlen(pfullname); 76 | if (pfullname[-1] != '\\') 77 | *pfullname++ = '\\'; 78 | } 79 | else 80 | { 81 | *pfullname++ = 'a' - 1 + drive; 82 | *pfullname++ = ':'; 83 | } 84 | T_strcpy(pfullname, pdbname); 85 | T_strcpy(pdbstart, fullname); 86 | 87 | for(TCHAR*p = pdbstart; *p; p++) 88 | if (*p == '/') 89 | *p = '\\'; 90 | 91 | // remove relative parts "./" and "../" 92 | while (TCHAR* p = T_strstr (pdbstart, TEXT("\\.\\"))) 93 | T_strcpy(p, p + 2); 94 | 95 | while (TCHAR* p = T_strstr (pdbstart, TEXT("\\..\\"))) 96 | { 97 | for (TCHAR* q = p - 1; q >= pdbstart; q--) 98 | if (*q == '\\') 99 | { 100 | T_strcpy(q, p + 3); 101 | break; 102 | } 103 | } 104 | } 105 | 106 | int dumpObjectFile(TCHAR* fname) 107 | { 108 | PEImage img; 109 | if (!img.readAll(fname)) 110 | fatal(SARG ": %s", fname, img.getLastError()); 111 | 112 | img.initDWARFObject(); 113 | if(img.debug_line.isPresent()) 114 | { 115 | if (!interpretDWARFLines(img, 0)) 116 | fatal(SARG ": cannot dump line numbers", fname); 117 | } 118 | else if (img.dumpDebugLineInfoOMF() < 0) 119 | img.dumpDebugLineInfoCOFF(); 120 | 121 | return 0; 122 | } 123 | 124 | int T_main(int argc, TCHAR* argv[]) 125 | { 126 | if (argc < 2) 127 | { 128 | printf("Dump line information for object files in OMF/CV4, COFF/CV8 or COFF/DWARF format, Version %g\n", VERSION); 129 | printf("Copyright (c) 2015 by Rainer Schuetze, All Rights Reserved\n"); 130 | printf("\n"); 131 | printf("License for redistribution is given by the Artistic License 2.0\n"); 132 | printf("see file LICENSE for further details\n"); 133 | printf("\n"); 134 | printf("usage: " SARG " \n", argv[0]); 135 | return -1; 136 | } 137 | 138 | return dumpObjectFile(argv[1]); 139 | } 140 | -------------------------------------------------------------------------------- /src/dumplines.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {6434537D-446A-4C99-9829-135F7C000D90} 15 | dumpLines 16 | Win32Proj 17 | 18 | $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder) 19 | $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder) 20 | $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion) 21 | $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion) 22 | 23 | $(WindowsTargetPlatformVersion_10).0 24 | $(WindowsTargetPlatformVersion_10) 25 | 26 | 27 | 28 | Application 29 | $(DefaultPlatformToolset) 30 | Unicode 31 | true 32 | 33 | 34 | Application 35 | $(DefaultPlatformToolset) 36 | Unicode 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | <_ProjectFileVersion>12.0.21005.1 50 | 51 | 52 | ..\bin\$(Configuration)\ 53 | ..\bin\$(Configuration)\$(ProjectName)\ 54 | true 55 | 56 | 57 | ..\bin\$(Configuration)\ 58 | ..\bin\$(Configuration)\$(ProjectName)\ 59 | false 60 | 61 | 62 | 63 | /wd4996 %(AdditionalOptions) 64 | Disabled 65 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 66 | true 67 | EnableFastChecks 68 | MultiThreadedDebug 69 | false 70 | 71 | Level3 72 | EditAndContinue 73 | 74 | 75 | dbghelp.lib;%(AdditionalDependencies) 76 | $(OutDir)$(ProjectName).exe 77 | true 78 | Console 79 | MachineX86 80 | 5.1 81 | 82 | 83 | 84 | 85 | /wd4996 %(AdditionalOptions) 86 | MaxSpeed 87 | true 88 | Speed 89 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | MultiThreaded 91 | true 92 | false 93 | 94 | Level3 95 | ProgramDatabase 96 | 97 | 98 | true 99 | Console 100 | true 101 | true 102 | MachineX86 103 | true 104 | 5.1 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/dviewhelper/dviewhelper.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // DViewHelper - Expression Evaluator for the D string and object class 4 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 5 | // 6 | // License for redistribution is given by the Artistic License 2.0 7 | // see file LICENSE for further details 8 | // 9 | // Compile the DLL and add the following lines to AUTOEXP.DAT in section [AutoExpand] 10 | // string_viewhelper=$ADDIN(\dviewhelper.dll,_DStringView@28) 11 | // wstring_viewhelper=$ADDIN(\dviewhelper.dll,_DWStringView@28) 12 | // dstring_viewhelper=$ADDIN(\dviewhelper.dll,_DDStringView@28) 13 | // object_viewhelper=$ADDIN(\dviewhelper.dll,_DObjectView@28) 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | 17 | #define _CRT_SECURE_NO_WARNINGS 18 | 19 | #include 20 | #include 21 | 22 | extern "C" { 23 | 24 | // Copied from MSDN 25 | struct DEBUGHELPER 26 | { 27 | DWORD dwVersion; 28 | HRESULT (WINAPI *ReadDebuggeeMemory)(DEBUGHELPER *pThis, DWORD dwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot); 29 | // from here only when dwVersion >= 0x20000 30 | DWORDLONG (WINAPI *GetRealAddress)(DEBUGHELPER *pThis); 31 | HRESULT (WINAPI *ReadDebuggeeMemoryEx)(DEBUGHELPER *pThis, DWORDLONG qwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot); 32 | int (WINAPI *GetProcessorType)(DEBUGHELPER *pThis); 33 | }; 34 | 35 | // possible processor types 36 | typedef enum _MPT { 37 | mptix86 = 0, // Intel X86 38 | mptia64 = 1, // Intel Merced 39 | mptamd64 = 2, // AMD64 40 | mptUnknown = 3 // Unknown 41 | } MPT; 42 | 43 | HRESULT readMem(DEBUGHELPER *pHelper, DWORDLONG qwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot) 44 | { 45 | if(pHelper->dwVersion < 0x20000) 46 | return pHelper->ReadDebuggeeMemory(pHelper, (DWORD)qwAddr, nWant, pWhere, nGot); 47 | return pHelper->ReadDebuggeeMemoryEx(pHelper, qwAddr, nWant, pWhere, nGot); 48 | } 49 | 50 | struct DString 51 | { 52 | DWORD length; 53 | DWORD data; 54 | }; 55 | 56 | /////////////////////////////////////////////////////////////////////////////// 57 | 58 | HRESULT WINAPI StringView(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, 59 | char *pResult, size_t max, DWORD sizePerChar) 60 | { 61 | DWORDLONG qwAddress = dwAddress; 62 | if(pHelper->dwVersion >= 0x20000) 63 | qwAddress = pHelper->GetRealAddress(pHelper); 64 | 65 | int proc = 0; 66 | if(pHelper->dwVersion >= 0x20000) 67 | proc = pHelper->GetProcessorType(pHelper); 68 | int sizeOfPtr = proc == 0 ? 4 : 8; 69 | 70 | // Get the string struct 71 | char strdata[16]; 72 | DWORD read; 73 | if (readMem(pHelper, qwAddress, 2*sizeOfPtr, strdata, &read) != S_OK) 74 | { 75 | strncpy(pResult,"Cannot access struct", max); 76 | return S_OK; 77 | } 78 | DWORDLONG length, data; 79 | if(sizeOfPtr > 4) 80 | { 81 | length = *(DWORDLONG*) strdata; 82 | data = *(DWORDLONG*) (strdata + sizeOfPtr); 83 | } 84 | else 85 | { 86 | length = *(DWORD*) strdata; 87 | data = *(DWORD*) (strdata + sizeOfPtr); 88 | } 89 | if (length == 0) 90 | { 91 | strncpy(pResult,"\"\"", max); 92 | return S_OK; 93 | } 94 | 95 | char* pData = pResult + 1; 96 | DWORD cnt = (length < max - 3 ? (DWORD)length : max - 3); 97 | if (sizePerChar * cnt > max) 98 | pData = new char[sizePerChar * cnt]; 99 | 100 | if (readMem(pHelper, data, sizePerChar * cnt, pData, &read) != S_OK) 101 | { 102 | strncpy(pResult,"Cannot access data", max); 103 | } 104 | else 105 | { 106 | //! @todo: proper utf8/16/32 translation 107 | for (DWORD p = 0; p < cnt; p++) 108 | { 109 | int ch; 110 | if (sizePerChar == 4) 111 | ch = ((long*) pData) [p]; 112 | else if (sizePerChar == 2) 113 | ch = ((short*) pData) [p]; 114 | else 115 | ch = pData [p]; 116 | 117 | if (ch >= 128 && ch < -128) 118 | pResult[p + 1] = -1; 119 | else 120 | pResult[p + 1] = (char) ch; 121 | } 122 | pResult[0] = '\"'; 123 | pResult[cnt+1] = '\"'; 124 | pResult[cnt+2] = 0; 125 | } 126 | 127 | if(pData != pResult + 1) 128 | delete [] pData; 129 | return S_OK; 130 | } 131 | 132 | 133 | __declspec(dllexport) 134 | HRESULT WINAPI DStringView(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, 135 | char *pResult, size_t max, DWORD reserved) 136 | { 137 | return StringView(dwAddress, pHelper, nBase, bUniStrings, pResult, max, 1); 138 | } 139 | 140 | __declspec(dllexport) 141 | HRESULT WINAPI DWStringView(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, 142 | char *pResult, size_t max, DWORD reserved) 143 | { 144 | return StringView(dwAddress, pHelper, nBase, bUniStrings, pResult, max, 2); 145 | } 146 | 147 | __declspec(dllexport) 148 | HRESULT WINAPI DDStringView(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, 149 | char *pResult, size_t max, DWORD reserved) 150 | { 151 | return StringView(dwAddress, pHelper, nBase, bUniStrings, pResult, max, 4); 152 | } 153 | 154 | __declspec(dllexport) 155 | HRESULT WINAPI DObjectView(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, 156 | char *pResult, size_t max, DWORD reserved) 157 | { 158 | DWORDLONG qwAddress = dwAddress; 159 | if(pHelper->dwVersion >= 0x20000) 160 | qwAddress = pHelper->GetRealAddress(pHelper); 161 | 162 | if(qwAddress == 0) 163 | { 164 | strncpy(pResult,"null", max); 165 | return S_OK; 166 | } 167 | 168 | int proc = 0; 169 | if(pHelper->dwVersion >= 0x20000) 170 | proc = pHelper->GetProcessorType(pHelper); 171 | int sizeOfPtr = proc == 0 ? 4 : 8; 172 | 173 | DWORD read; 174 | DWORDLONG vtablePtr = 0; 175 | if (readMem(pHelper, qwAddress, sizeOfPtr, &vtablePtr, &read) != S_OK) 176 | { 177 | strncpy(pResult,"Cannot access object", max); 178 | return S_OK; 179 | } 180 | DWORDLONG classinfoPtr = 0; 181 | if (readMem(pHelper, vtablePtr, sizeOfPtr, &classinfoPtr, &read) != S_OK) 182 | { 183 | strncpy(pResult,"Cannot access vtable", max); 184 | return S_OK; 185 | } 186 | char strdata[16]; 187 | if (readMem(pHelper, classinfoPtr + 4*sizeOfPtr, 2*sizeOfPtr, strdata, &read) != S_OK) 188 | { 189 | strncpy(pResult,"Cannot access class info", max); 190 | return S_OK; 191 | } 192 | 193 | DWORDLONG length, data; 194 | if(sizeOfPtr > 4) 195 | { 196 | length = *(DWORDLONG*) strdata; 197 | data = *(DWORDLONG*) (strdata + sizeOfPtr); 198 | } 199 | else 200 | { 201 | length = *(DWORD*) strdata; 202 | data = *(DWORD*) (strdata + sizeOfPtr); 203 | } 204 | DWORD cnt = (DWORD)(length < max - 1 ? length : max - 1); 205 | if (readMem(pHelper, data, cnt, pResult, &read) != S_OK) 206 | { 207 | strncpy(pResult,"Cannot access name data", max); 208 | return S_OK; 209 | } 210 | 211 | pResult[cnt] = 0; 212 | return S_OK; 213 | } 214 | 215 | // avoid unloading the DLL with every expression 216 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 217 | { 218 | if(fdwReason == DLL_PROCESS_ATTACH) 219 | { 220 | TCHAR moduleName[1024]; 221 | 222 | if(GetModuleFileName(hinstDLL, moduleName, sizeof(moduleName)/ sizeof(TCHAR))) 223 | LoadLibrary(moduleName); 224 | } 225 | return TRUE; 226 | } 227 | 228 | } // extern "C" 229 | -------------------------------------------------------------------------------- /src/dviewhelper/dviewhelper.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 25 | 28 | 31 | 34 | 37 | 40 | 52 | 55 | 58 | 61 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 94 | 102 | 105 | 108 | 111 | 114 | 117 | 126 | 129 | 132 | 135 | 147 | 150 | 153 | 156 | 159 | 162 | 165 | 168 | 169 | 170 | 171 | 172 | 173 | 178 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /src/dviewhelper/dviewhelper.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {E4424774-A7A0-4502-8626-2723904D70EA} 15 | Win32Proj 16 | 17 | $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder) 18 | $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder) 19 | $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion) 20 | $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion) 21 | 22 | $(WindowsTargetPlatformVersion_10).0 23 | $(WindowsTargetPlatformVersion_10) 24 | 25 | 26 | 27 | DynamicLibrary 28 | $(DefaultPlatformToolset) 29 | MultiByte 30 | 31 | 32 | DynamicLibrary 33 | $(DefaultPlatformToolset) 34 | MultiByte 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | <_ProjectFileVersion>12.0.21005.1 49 | 50 | 51 | ../../bin/$(Configuration)\ 52 | $(OutDir)$(ProjectName)\ 53 | true 54 | 55 | 56 | ../../bin/$(Configuration)\ 57 | $(OutDir)$(ProjectName)\ 58 | false 59 | 60 | 61 | 62 | Disabled 63 | WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 64 | true 65 | EnableFastChecks 66 | MultiThreadedDebug 67 | 68 | Level3 69 | EditAndContinue 70 | 71 | 72 | $(OutDir)$(ProjectName).dll 73 | 74 | true 75 | Windows 76 | false 77 | 78 | MachineX86 79 | 80 | 81 | 82 | 83 | WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 84 | MultiThreaded 85 | 86 | Level3 87 | ProgramDatabase 88 | 89 | 90 | $(OutDir)$(ProjectName).dll 91 | true 92 | Windows 93 | true 94 | true 95 | false 96 | 97 | MachineX86 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/dviewhelper/dviewhelper.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #include "PEImage.h" 8 | #include "cv2pdb.h" 9 | #include "symutil.h" 10 | 11 | #include 12 | 13 | double 14 | #include "../VERSION" 15 | ; 16 | 17 | #ifdef UNICODE 18 | #define T_toupper towupper 19 | #define T_getdcwd _wgetdcwd 20 | #define T_strlen wcslen 21 | #define T_strcpy wcscpy 22 | #define T_strncpy wcsncpy 23 | #define T_strcat wcscat 24 | #define T_strstr wcsstr 25 | #define T_strncmp wcsncmp 26 | #define T_strtoul wcstoul 27 | #define T_strtod wcstod 28 | #define T_strrchr wcsrchr 29 | #define T_unlink _wremove 30 | #define T_main wmain 31 | #define SARG "%S" 32 | #define T_stat _wstat 33 | #else 34 | #define T_toupper toupper 35 | #define T_getdcwd _getdcwd 36 | #define T_strlen strlen 37 | #define T_strcpy strcpy 38 | #define T_strncpy strncpy 39 | #define T_strcat strcat 40 | #define T_strstr strstr 41 | #define T_strncmp strncmp 42 | #define T_strtoul strtoul 43 | #define T_strtod strtod 44 | #define T_strrchr strrchr 45 | #define T_unlink unlink 46 | #define T_main main 47 | #define SARG "%s" 48 | #define T_stat stat 49 | #endif 50 | 51 | void fatal(const char *message, ...) 52 | { 53 | va_list argptr; 54 | va_start(argptr, message); 55 | vprintf(message, argptr); 56 | va_end(argptr); 57 | printf("\n"); 58 | exit(1); 59 | } 60 | 61 | bool makefullpath(TCHAR* pdbname, const TCHAR* basename = NULL) 62 | { 63 | TCHAR* pdbstart = pdbname; 64 | TCHAR fullname[260]; 65 | TCHAR* pfullname = fullname; 66 | 67 | if (!pdbname || T_strlen(pdbname) < 2) 68 | { 69 | return false; 70 | } 71 | // If the path starts with "\\\\", it is considered to be a full path, such as UNC path, VolumeGUID path: "\\\\?\\Volume" 72 | if (pdbname[0] == '\\' && pdbname[1] == '\\') 73 | { 74 | return false; 75 | } 76 | 77 | int drive = 0; 78 | if (pdbname[0] && pdbname[1] == ':') 79 | { 80 | if (pdbname[2] == '\\' || pdbname[2] == '/') 81 | return false; 82 | drive = T_toupper (pdbname[0]) - 'A' + 1; 83 | pdbname += 2; 84 | } 85 | else 86 | { 87 | drive = _getdrive(); 88 | } 89 | 90 | if (*pdbname != '\\' && *pdbname != '/') 91 | { 92 | if (basename) { 93 | const TCHAR* pPathEnd = T_strrchr(basename, '/'); 94 | if (!pPathEnd) 95 | pPathEnd = T_strrchr(basename, '\\'); 96 | if (pPathEnd) { 97 | auto len = pPathEnd - basename + 1; 98 | T_strncpy(pfullname, basename, len); 99 | pfullname += len; 100 | pfullname[0] = TEXT('\0'); 101 | } 102 | } 103 | if (pfullname == fullname) { 104 | T_getdcwd(drive, pfullname, sizeof(fullname) / sizeof(fullname[0]) - 2); 105 | pfullname += T_strlen(pfullname); 106 | if (pfullname[-1] != '\\') 107 | *pfullname++ = '\\'; 108 | } 109 | } 110 | else 111 | { 112 | *pfullname++ = 'a' - 1 + drive; 113 | *pfullname++ = ':'; 114 | } 115 | T_strcpy(pfullname, pdbname); 116 | T_strcpy(pdbstart, fullname); 117 | 118 | for(TCHAR*p = pdbstart; *p; p++) 119 | if (*p == '/') 120 | *p = '\\'; 121 | 122 | // remove relative parts "./" and "../" 123 | while (TCHAR* p = T_strstr (pdbstart, TEXT("\\.\\"))) 124 | T_strcpy(p, p + 2); 125 | 126 | while (TCHAR* p = T_strstr (pdbstart, TEXT("\\..\\"))) 127 | { 128 | for (TCHAR* q = p - 1; q >= pdbstart; q--) 129 | if (*q == '\\') 130 | { 131 | T_strcpy(q, p + 3); 132 | break; 133 | } 134 | } 135 | return true; 136 | } 137 | 138 | TCHAR* changeExtension(TCHAR* dbgname, const TCHAR* exename, const TCHAR* ext) 139 | { 140 | T_strcpy(dbgname, exename); 141 | TCHAR *pDot = T_strrchr(dbgname, '.'); 142 | if (!pDot || pDot <= T_strrchr(dbgname, '/') || pDot <= T_strrchr(dbgname, '\\')) 143 | T_strcat(dbgname, ext); 144 | else 145 | T_strcpy(pDot, ext); 146 | return dbgname; 147 | } 148 | 149 | TCHAR* extractDebugLink(const PEImage& img, TCHAR* dbgname, const TCHAR* exename, const TCHAR* debug_link = NULL) 150 | { 151 | if (debug_link) 152 | { 153 | T_strcpy(dbgname, debug_link); 154 | } 155 | else 156 | { 157 | #ifdef UNICODE 158 | auto copied = MultiByteToWideChar(CP_UTF8, 0, (const char*)img.gnu_debuglink.startByte(), img.gnu_debuglink.length, dbgname, MAX_PATH); 159 | if (copied < MAX_PATH) 160 | dbgname[copied] = L'\0'; 161 | else 162 | dbgname[0] = L'\0'; 163 | #else 164 | if (exe.gnu_debuglink.length < MAX_PATH) { 165 | strncpy((char*)dbgname, (const char*)exe.gnu_debuglink.startByte(), exe.gnu_debuglink.length); 166 | dbgname[exe.gnu_debuglink.length] = '\0'; 167 | } 168 | else 169 | dbgname[0] = '\0'; 170 | #endif 171 | } 172 | 173 | struct _stat buffer; 174 | TCHAR fulldbgname[MAX_PATH]; 175 | T_strcpy(fulldbgname, dbgname); 176 | if (makefullpath(fulldbgname, exename) && T_stat(fulldbgname, &buffer) != 0) 177 | { 178 | // If path conversion took place and file does not exist, prepend ".debug\" and try again 179 | T_strcpy(fulldbgname, TEXT(".debug\\")); 180 | T_strcat(fulldbgname, dbgname); 181 | makefullpath(fulldbgname, exename); 182 | } 183 | T_strcpy(dbgname, fulldbgname); 184 | return dbgname; 185 | } 186 | 187 | int T_main(int argc, TCHAR* argv[]) 188 | { 189 | double Dversion = 2.072; 190 | const TCHAR* pdbref = 0; 191 | const TCHAR* debug_link = 0; 192 | DebugLevel debug = DebugLevel{}; 193 | 194 | CoInitialize(nullptr); 195 | 196 | while (argc > 1 && argv[1][0] == '-') 197 | { 198 | argv++; 199 | argc--; 200 | if (argv[0][1] == '-') 201 | break; 202 | if (argv[0][1] == 'D') 203 | Dversion = T_strtod(argv[0] + 2, 0); 204 | else if (argv[0][1] == 'C') 205 | Dversion = 0; 206 | else if (argv[0][1] == 'n') 207 | demangleSymbols = false; 208 | else if (argv[0][1] == 'e') 209 | useTypedefEnum = true; 210 | else if (!T_strncmp(&argv[0][1], TEXT("debug"), 5)) // debug[level] 211 | { 212 | debug = (DebugLevel)T_strtoul(&argv[0][6], 0, 0); 213 | if (!debug) { 214 | debug = DbgBasic; 215 | } 216 | 217 | fprintf(stderr, "Debug set to %x\n", debug); 218 | } 219 | else if (argv[0][1] == 's' && argv[0][2]) 220 | dotReplacementChar = (char)argv[0][2]; 221 | else if (argv[0][1] == 'p' && argv[0][2]) 222 | pdbref = argv[0] + 2; 223 | else if (argv[0][1] == 'l' && argv[0][2]) 224 | debug_link = argv[0] + 2; 225 | else 226 | fatal("unknown option: " SARG, argv[0]); 227 | } 228 | 229 | if (argc < 2) 230 | { 231 | printf("Convert DMD CodeView/DWARF debug information to PDB files, Version %.02f\n", VERSION); 232 | printf("Copyright (c) 2009-2012 by Rainer Schuetze, All Rights Reserved\n"); 233 | printf("\n"); 234 | printf("License for redistribution is given by the Artistic License 2.0\n"); 235 | printf("see file LICENSE for further details\n"); 236 | printf("\n"); 237 | printf("usage: " SARG " [-D|-C|-n|-e|-s|-p|-l] [new-exe-file] [pdb-file]\n", argv[0]); 238 | return -1; 239 | } 240 | 241 | PEImage exe, dbg, *img = NULL; 242 | TCHAR dbgname[MAX_PATH]; 243 | 244 | if (!exe.loadExe(argv[1])) 245 | fatal(SARG ": %s", argv[1], exe.getLastError()); 246 | if (exe.countCVEntries() || exe.hasDWARF()) 247 | img = &exe; 248 | else 249 | { 250 | struct _stat buffer; 251 | 252 | if (debug_link || exe.hasDebugLink()) 253 | { 254 | img = &exe; 255 | extractDebugLink(exe, dbgname, argv[1], debug_link); 256 | } 257 | else { 258 | img = &dbg; 259 | changeExtension(dbgname, argv[1], TEXT(".dbg")); 260 | } 261 | // try separate debug file 262 | if (T_stat(dbgname, &buffer) != 0) 263 | fatal(SARG ": no debug entries found", argv[1]); 264 | if (!dbg.loadExe(dbgname)) 265 | fatal(SARG ": %s", dbgname, dbg.getLastError()); 266 | if (dbg.countCVEntries() == 0 && !dbg.hasDWARF()) 267 | fatal(SARG ": no debug entries found", dbgname); 268 | } 269 | 270 | CV2PDB cv2pdb(*img, dbg.hasDWARF() ? &dbg : NULL, debug); 271 | cv2pdb.Dversion = Dversion; 272 | cv2pdb.initLibraries(); 273 | 274 | TCHAR* outname = argv[1]; 275 | if (argc > 2 && argv[2][0]) 276 | outname = argv[2]; 277 | 278 | TCHAR pdbname[260]; 279 | if (argc > 3) 280 | T_strcpy (pdbname, argv[3]); 281 | else 282 | { 283 | T_strcpy (pdbname, outname); 284 | TCHAR *pDot = T_strrchr (pdbname, '.'); 285 | if (!pDot || pDot <= T_strrchr (pdbname, '/') || pDot <= T_strrchr (pdbname, '\\')) 286 | T_strcat (pdbname, TEXT(".pdb")); 287 | else 288 | T_strcpy (pDot, TEXT(".pdb")); 289 | } 290 | makefullpath(pdbname); 291 | 292 | T_unlink(pdbname); 293 | 294 | if(!cv2pdb.openPDB(pdbname, pdbref)) 295 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 296 | 297 | if(exe.hasDWARF() || dbg.hasDWARF()) 298 | { 299 | if(!exe.relocateDebugLineInfo(0x400000)) 300 | fatal(SARG ": %s", argv[1], cv2pdb.getLastError()); 301 | 302 | if(!cv2pdb.createDWARFModules()) 303 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 304 | 305 | if(!cv2pdb.addDWARFTypes()) 306 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 307 | 308 | if(!cv2pdb.addDWARFLines()) 309 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 310 | 311 | if (!cv2pdb.addDWARFPublics()) 312 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 313 | 314 | if (!cv2pdb.writeDWARFImage(outname)) 315 | fatal(SARG ": %s", outname, cv2pdb.getLastError()); 316 | } 317 | else 318 | { 319 | if (!cv2pdb.initSegMap()) 320 | fatal(SARG ": %s", argv[1], cv2pdb.getLastError()); 321 | 322 | if (!cv2pdb.initGlobalSymbols()) 323 | fatal(SARG ": %s", argv[1], cv2pdb.getLastError()); 324 | 325 | if (!cv2pdb.initGlobalTypes()) 326 | fatal(SARG ": %s", argv[1], cv2pdb.getLastError()); 327 | 328 | if (!cv2pdb.createModules()) 329 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 330 | 331 | if (!cv2pdb.addTypes()) 332 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 333 | 334 | if (!cv2pdb.addSymbols()) 335 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 336 | 337 | if (!cv2pdb.addSrcLines()) 338 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 339 | 340 | if (!cv2pdb.addPublics()) 341 | fatal(SARG ": %s", pdbname, cv2pdb.getLastError()); 342 | 343 | if (!exe.isDBG()) 344 | if (!cv2pdb.writeImage(outname, exe)) 345 | fatal(SARG ": %s", outname, cv2pdb.getLastError()); 346 | } 347 | 348 | return 0; 349 | } 350 | -------------------------------------------------------------------------------- /src/managed/cv2pdb.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 27 | 30 | 33 | 36 | 39 | 42 | 57 | 60 | 63 | 66 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 97 | 98 | 107 | 110 | 113 | 116 | 119 | 122 | 136 | 139 | 142 | 145 | 154 | 157 | 160 | 163 | 166 | 169 | 172 | 175 | 176 | 177 | 178 | 179 | 180 | 185 | 188 | 189 | 192 | 193 | 196 | 197 | 200 | 201 | 204 | 205 | 208 | 209 | 212 | 213 | 216 | 217 | 220 | 221 | 224 | 225 | 228 | 229 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | -------------------------------------------------------------------------------- /src/managed/main.cpp: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | // CLR interface to cv2pdb created by Alexander Bothe 8 | 9 | #include "../PEImage.h" 10 | #include "../cv2pdb.h" 11 | #include "vcclr.h" 12 | 13 | using namespace System; 14 | using namespace System::IO; 15 | using namespace System::Text; 16 | 17 | namespace CodeViewToPDB 18 | { 19 | ///

Exports DMD CodeView debug information from an executable file to a separate .pdb file 20 | public ref class CodeViewToPDBConverter 21 | { 22 | public: 23 | delegate void MsgHandler(String^ Message); 24 | ///If an error occurs it will be reported via this event 25 | static event MsgHandler^ Message; 26 | 27 | ///Exports DMD CodeView debug information from an executable file to a separate .pdb file 28 | static bool DoConvert(String^ InputExe,String^ OutputExe,String^ OutputPDBFile,bool IsD2) 29 | { 30 | if(!File::Exists(InputExe)) 31 | { 32 | Message("Input file doesn't exist!"); 33 | return false; 34 | } 35 | 36 | if(String::IsNullOrEmpty(OutputPDBFile) || String::IsNullOrEmpty(OutputExe)) 37 | { 38 | Message("Empty arguments not allowed!"); 39 | return false; 40 | } 41 | 42 | char* input=(char*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(InputExe).ToPointer(); 43 | char* outname=(char*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(OutputExe).ToPointer(); 44 | char* pdbname=(char*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(OutputPDBFile).ToPointer(); 45 | 46 | PEImage img(input); 47 | 48 | if (img.countCVEntries() == 0) 49 | { 50 | Message("No codeview debug entries found"); 51 | return false; 52 | } 53 | 54 | CV2PDB cv2pdb(img); 55 | cv2pdb.initLibraries(); 56 | cv2pdb.Dversion = IsD2?2:1; 57 | 58 | File::Delete(OutputPDBFile); 59 | 60 | if(cv2pdb.openPDB(pdbname) 61 | && cv2pdb.initSegMap() 62 | && cv2pdb.initGlobalTypes() 63 | && cv2pdb.createModules() 64 | && cv2pdb.addTypes() 65 | && cv2pdb.addSymbols() 66 | && cv2pdb.addSrcLines() 67 | && cv2pdb.addPublics() 68 | && cv2pdb.writeImage(outname)) 69 | { } 70 | else 71 | { 72 | Message(gcnew String(cv2pdb.getLastError())); 73 | return false; 74 | } 75 | 76 | return true; 77 | } 78 | 79 | static bool DoConvert(String^ Exe,String^ OutputPDBFile) 80 | { 81 | return DoConvert(Exe,Exe,OutputPDBFile,true); 82 | } 83 | 84 | static bool DoConvert(String^ Exe) 85 | { 86 | return DoConvert(Exe,Exe,Path::ChangeExtension(Exe,".pdb"),true); 87 | } 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /src/mspdb.cpp: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #include "mspdb.h" 8 | 9 | #include 10 | #include 11 | #include "packages/Microsoft.VisualStudio.Setup.Configuration.Native.1.16.30/lib/native/include/Setup.Configuration.h" 12 | #include 13 | #include 14 | 15 | _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); 16 | _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); 17 | _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); 18 | 19 | #pragma comment(lib, "rpcrt4.lib") 20 | 21 | HMODULE modMsPdb; 22 | mspdb::fnPDBOpen2W *pPDBOpen2W; 23 | 24 | char* mspdb80_dll = "mspdb80.dll"; 25 | char* mspdb100_dll = "mspdb100.dll"; 26 | char* mspdb110_dll = "mspdb110.dll"; 27 | char* mspdb120_dll = "mspdb120.dll"; 28 | char* mspdb140_dll = "mspdb140.dll"; 29 | // char* mspdb110shell_dll = "mspdbst.dll"; // the VS 2012 Shell uses this file instead of mspdb110.dll, but is missing mspdbsrv.exe 30 | 31 | int mspdb::vsVersion = 8; 32 | 33 | // verify mspdbsrv.exe is found in the same path 34 | void tryLoadLibrary(const char* mspdb) 35 | { 36 | if (modMsPdb) 37 | return; 38 | modMsPdb = LoadLibraryA(mspdb); 39 | if (!modMsPdb) 40 | return; 41 | 42 | char modpath[260]; 43 | if(GetModuleFileNameA(modMsPdb, modpath, 260) < 260) 44 | { 45 | char* p = modpath + strlen(modpath); 46 | while(p > modpath && p[-1] != '\\') 47 | p--; 48 | strcpy(p, "mspdbsrv.exe"); 49 | if(GetFileAttributesA(modpath) != INVALID_FILE_ATTRIBUTES) 50 | return; 51 | } 52 | FreeLibrary(modMsPdb); 53 | modMsPdb = NULL; 54 | } 55 | 56 | #if _M_X64 57 | #define KEY_OPEN_FLAGS KEY_QUERY_VALUE | KEY_WOW64_32KEY 58 | #else 59 | #define KEY_OPEN_FLAGS KEY_QUERY_VALUE 60 | #endif 61 | 62 | bool getInstallDir(const char* version, char* installDir, DWORD size) 63 | { 64 | char key[260] = "SOFTWARE\\Microsoft\\"; 65 | strcat(key, version); 66 | 67 | HKEY hkey; 68 | if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_OPEN_FLAGS, &hkey) != ERROR_SUCCESS) 69 | return false; 70 | 71 | bool rc = RegQueryValueExA(hkey, "InstallDir", 0, 0, (LPBYTE)installDir, &size) == ERROR_SUCCESS; 72 | RegCloseKey(hkey); 73 | return rc; 74 | } 75 | 76 | bool tryLoadMsPdb(const char* version, const char* mspdb, const char* path = 0) 77 | { 78 | char installDir[260]; 79 | if (!getInstallDir(version, installDir, sizeof(installDir))) 80 | return false; 81 | char* p = installDir + strlen(installDir); 82 | if (p[-1] != '\\' && p[-1] != '/') 83 | *p++ = '\\'; 84 | if(path) 85 | p += strlen(strcpy(p, path)); 86 | strcpy(p, mspdb); 87 | 88 | tryLoadLibrary(installDir); 89 | return modMsPdb != 0; 90 | } 91 | 92 | bool tryLoadMsPdbCom(const char* mspdb, const char* path = 0) 93 | { 94 | ISetupConfigurationPtr query; 95 | ISetupInstancePtr instance; 96 | IEnumSetupInstancesPtr instances; 97 | BSTR installDir; 98 | unsigned long fetched; 99 | 100 | auto result = query.CreateInstance(__uuidof(SetupConfiguration)); 101 | if (FAILED(result) || !query) 102 | return false; 103 | if (FAILED(query->EnumInstances(&instances))) 104 | return false; 105 | 106 | while (!modMsPdb) 107 | { 108 | if (FAILED(instances->Next(1, &instance, &fetched)) || !fetched) 109 | return false; 110 | 111 | if (FAILED(instance->GetInstallationPath(&installDir))) 112 | continue; 113 | 114 | char modpath[260]; 115 | WideCharToMultiByte(CP_ACP, 0, installDir, -1, modpath, 260, NULL, NULL); 116 | SysFreeString(installDir); 117 | 118 | #ifdef _WIN64 119 | strncat(modpath, "\\VC\\Tools\\MSVC\\*", 260); 120 | WIN32_FIND_DATAA data; 121 | HANDLE hFind = FindFirstFileA(modpath, &data); // DIRECTORY 122 | 123 | if (hFind != INVALID_HANDLE_VALUE) 124 | { 125 | int len = strlen(modpath) - 1; 126 | do 127 | { 128 | modpath[len] = 0; 129 | strncat(modpath, data.cFileName, 260); 130 | strncat(modpath, "\\bin\\Hostx64\\x64\\", 260); 131 | strncat(modpath, mspdb, 260); 132 | tryLoadLibrary(modpath); 133 | } 134 | while (!modMsPdb && FindNextFileA(hFind, &data)); 135 | FindClose(hFind); 136 | } 137 | 138 | #else 139 | strncat(modpath, "\\Common7\\IDE\\", 260); // wrong path for x64 build of cv2pdb 140 | strncat(modpath, mspdb, 260); 141 | tryLoadLibrary(modpath); 142 | #endif 143 | } 144 | 145 | return true; 146 | } 147 | 148 | bool tryLoadMsPdbVS2017(const char* mspdb, const char* path = 0) 149 | { 150 | const char* key = "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7"; 151 | 152 | HKEY hkey; 153 | if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_OPEN_FLAGS, &hkey) != ERROR_SUCCESS) 154 | return false; 155 | 156 | char installDir[260]; 157 | DWORD size = sizeof(installDir); 158 | bool rc = RegQueryValueExA(hkey, "15.0", 0, 0, (LPBYTE)installDir, &size) == ERROR_SUCCESS; 159 | RegCloseKey(hkey); 160 | if(!rc) 161 | return false; 162 | 163 | strncat(installDir, "Common7\\IDE\\", 260); // wrong path for x64 build of cv2pdb 164 | strncat(installDir, mspdb, 260); 165 | 166 | tryLoadLibrary(installDir); 167 | return modMsPdb != 0; 168 | } 169 | 170 | inline std::string& rtrim(std::string& s, const char* t = "\t\n\r ") 171 | { 172 | s.erase(s.find_last_not_of(t) + 1); 173 | return s; 174 | } 175 | 176 | bool tryLoadMsPdbVSWhere(const char* mspdb) 177 | { 178 | HANDLE read; 179 | HANDLE write; 180 | 181 | SECURITY_ATTRIBUTES securityAttributes = { 0 }; 182 | securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); 183 | securityAttributes.lpSecurityDescriptor = NULL; 184 | securityAttributes.bInheritHandle = TRUE; 185 | if(!CreatePipe(&read, &write, &securityAttributes, 0) || 186 | !SetHandleInformation(read, HANDLE_FLAG_INHERIT, 0)) 187 | return false; 188 | 189 | STARTUPINFOA startupInfo = { 0 }; 190 | startupInfo.cb = sizeof(startupInfo); 191 | startupInfo.dwFlags = STARTF_USESTDHANDLES; 192 | startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 193 | startupInfo.hStdOutput = write; 194 | startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); 195 | PROCESS_INFORMATION processInformation = { 0 }; 196 | ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION)); 197 | 198 | std::string vsPath; 199 | char buffer[1024] = ""; 200 | char commandLine[] = "vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath"; 201 | if(CreateProcessA("C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe", commandLine, NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &processInformation)) 202 | { 203 | CloseHandle(processInformation.hProcess); 204 | CloseHandle(processInformation.hThread); 205 | CloseHandle(write); 206 | 207 | DWORD length; 208 | if (ReadFile(read, buffer, sizeof(buffer) - 1, &length, NULL)) 209 | { 210 | buffer[length] = '\0'; 211 | vsPath += buffer; 212 | } 213 | } 214 | else 215 | CloseHandle(write); 216 | CloseHandle(read); 217 | rtrim(vsPath); 218 | if (vsPath.empty()) 219 | return false; 220 | 221 | // Read the version 222 | std::ifstream versionFile(vsPath + "\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"); 223 | if (versionFile.fail()) 224 | return false; 225 | std::string contents; 226 | contents.assign(std::istreambuf_iterator(versionFile), std::istreambuf_iterator()); 227 | versionFile.close(); 228 | rtrim(contents); 229 | 230 | std::string dllPath = vsPath + "\\VC\\Tools\\MSVC\\" + contents + "\\bin\\" + (sizeof(void*) == 8 ? "Hostx64\\x64\\" : "Hostx86\\x86\\") + mspdb; 231 | tryLoadLibrary(dllPath.c_str()); 232 | return modMsPdb != 0; 233 | } 234 | 235 | #ifdef _M_X64 236 | #define BIN_DIR_GE_VS12 "..\\..\\VC\\bin\\amd64\\" 237 | #define BIN_DIR_LT_VS12 BIN_DIR_GE_VS12 238 | #else 239 | #define BIN_DIR_GE_VS12 "..\\..\\VC\\bin\\" 240 | #define BIN_DIR_LT_VS12 0 241 | #endif 242 | 243 | void tryLoadMsPdb80(bool throughPath) 244 | { 245 | if (!modMsPdb && throughPath) 246 | tryLoadLibrary(mspdb80_dll); 247 | 248 | if (!modMsPdb && !throughPath) 249 | tryLoadMsPdb("VisualStudio\\9.0", mspdb80_dll, BIN_DIR_LT_VS12); 250 | if (!modMsPdb && !throughPath) 251 | tryLoadMsPdb("VisualStudio\\8.0", mspdb80_dll, BIN_DIR_LT_VS12); 252 | if (!modMsPdb && !throughPath) 253 | tryLoadMsPdb("VCExpress\\9.0", mspdb80_dll, BIN_DIR_LT_VS12); 254 | if (!modMsPdb && !throughPath) 255 | tryLoadMsPdb("VCExpress\\8.0", mspdb80_dll, BIN_DIR_LT_VS12); 256 | } 257 | 258 | void tryLoadMsPdb100(bool throughPath) 259 | { 260 | if (!modMsPdb) 261 | { 262 | if(throughPath) 263 | modMsPdb = LoadLibraryA(mspdb100_dll); 264 | if (!modMsPdb && !throughPath) 265 | tryLoadMsPdb("VisualStudio\\10.0", mspdb100_dll, BIN_DIR_LT_VS12); 266 | if (!modMsPdb && !throughPath) 267 | tryLoadMsPdb("VCExpress\\10.0", mspdb100_dll, BIN_DIR_LT_VS12); 268 | if (modMsPdb) 269 | mspdb::vsVersion = 10; 270 | } 271 | } 272 | 273 | void tryLoadMsPdb110(bool throughPath) 274 | { 275 | if (!modMsPdb) 276 | { 277 | if (throughPath) 278 | modMsPdb = LoadLibraryA(mspdb110_dll); 279 | if (!modMsPdb && !throughPath) 280 | tryLoadMsPdb("VisualStudio\\11.0", mspdb110_dll, BIN_DIR_LT_VS12); 281 | if (!modMsPdb && !throughPath) 282 | tryLoadMsPdb("VSWinExpress\\11.0", mspdb110_dll, BIN_DIR_LT_VS12); 283 | if (modMsPdb) 284 | mspdb::vsVersion = 11; 285 | } 286 | } 287 | 288 | void tryLoadMsPdb120(bool throughPath) 289 | { 290 | if (!modMsPdb) 291 | { 292 | if(throughPath) 293 | modMsPdb = LoadLibraryA(mspdb120_dll); 294 | if (!modMsPdb && !throughPath) 295 | tryLoadMsPdb("VisualStudio\\12.0", mspdb120_dll, BIN_DIR_GE_VS12); 296 | if (!modMsPdb && !throughPath) 297 | tryLoadMsPdb("VSWinExpress\\12.0", mspdb120_dll, BIN_DIR_GE_VS12); 298 | if (modMsPdb) 299 | mspdb::vsVersion = 12; 300 | } 301 | } 302 | 303 | void tryLoadMsPdb140(bool throughPath) 304 | { 305 | if (!modMsPdb) 306 | { 307 | if(throughPath) 308 | modMsPdb = LoadLibraryA(mspdb140_dll); 309 | if(!modMsPdb && !throughPath) 310 | tryLoadMsPdbCom(mspdb140_dll); 311 | if(!modMsPdb && !throughPath) 312 | tryLoadMsPdbVS2017(mspdb140_dll); 313 | if (!modMsPdb && !throughPath) 314 | tryLoadMsPdb("VisualStudio\\14.0", mspdb140_dll, BIN_DIR_GE_VS12); 315 | if (!modMsPdb && !throughPath) 316 | tryLoadMsPdb("VSWinExpress\\14.0", mspdb140_dll, BIN_DIR_GE_VS12); 317 | if (!modMsPdb && !throughPath) 318 | tryLoadMsPdbVSWhere(mspdb140_dll); 319 | if (modMsPdb) 320 | mspdb::vsVersion = 14; 321 | } 322 | } 323 | 324 | bool initMsPdb() 325 | { 326 | #if 0 // might cause problems when combining VS Shell 2010 with VS 2008 or similar 327 | if(const char* p = getenv("VisualStudioDir")) 328 | { 329 | // guess from environment variable from which version of VS we are invoked and prefer a correspondig mspdb DLL 330 | if (strstr(p, "2010")) 331 | tryLoadMsPdb100(); 332 | if (strstr(p, "2012")) 333 | tryLoadMsPdb110(); 334 | // VS2008 tried next anyway 335 | } 336 | #endif 337 | 338 | // try loading through the PATH first to best match current setup 339 | tryLoadMsPdb140(true); 340 | tryLoadMsPdb120(true); 341 | tryLoadMsPdb110(true); 342 | tryLoadMsPdb100(true); 343 | tryLoadMsPdb80(true); 344 | 345 | tryLoadMsPdb140(false); 346 | tryLoadMsPdb120(false); 347 | tryLoadMsPdb110(false); 348 | tryLoadMsPdb100(false); 349 | tryLoadMsPdb80(false); 350 | 351 | if (!modMsPdb) 352 | return false; 353 | 354 | if (!pPDBOpen2W) 355 | pPDBOpen2W = (mspdb::fnPDBOpen2W*) GetProcAddress(modMsPdb, "PDBOpen2W"); 356 | if (!pPDBOpen2W) 357 | return false; 358 | 359 | return true; 360 | } 361 | 362 | bool exitMsPdb() 363 | { 364 | pPDBOpen2W = 0; 365 | if (modMsPdb) 366 | FreeLibrary(modMsPdb); 367 | modMsPdb = 0; 368 | return true; 369 | } 370 | 371 | mspdb::PDB* CreatePDB(const wchar_t* pdbname) 372 | { 373 | if (!initMsPdb ()) 374 | return 0; 375 | 376 | mspdb::PDB* pdb = 0; 377 | long data[194] = { 193, 0 }; 378 | wchar_t ext[256] = L".exe"; 379 | if (!((*pPDBOpen2W) (pdbname, "wf", data, ext, 0x400, &pdb))) 380 | return 0; 381 | 382 | return pdb; 383 | } 384 | -------------------------------------------------------------------------------- /src/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/packages/Microsoft.VisualStudio.Setup.Configuration.Native.1.16.30/build/native/Microsoft.VisualStudio.Setup.Configuration.Native.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)..\..\lib\native\include\ 7 | 8 | 9 | 10 | 11 | %(AdditionalDependencies);Microsoft.VisualStudio.Setup.Configuration.Native.lib 12 | %(AdditionalLibraryDirectories);$(MSBuildThisFileDirectory)..\..\lib\native\$(PlatformToolset)\x86 13 | 14 | 15 | 16 | 17 | %(AdditionalDependencies);Microsoft.VisualStudio.Setup.Configuration.Native.lib 18 | %(AdditionalLibraryDirectories);$(MSBuildThisFileDirectory)..\..\lib\native\$(PlatformToolset)\x64 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/symutil.cpp: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #include 8 | 9 | #include "symutil.h" 10 | #include "demangle.h" 11 | 12 | extern "C" { 13 | #include "mscvpdb.h" 14 | } 15 | 16 | #include 17 | 18 | char dotReplacementChar = '@'; 19 | bool demangleSymbols = true; 20 | bool useTypedefEnum = false; 21 | 22 | int dsym2c(const BYTE* p, int len, char* cname, int maxclen) 23 | { 24 | const BYTE* beg = p; 25 | const BYTE* end = p + len; 26 | int zlen, zpos, cpos = 0; 27 | 28 | // decompress symbol 29 | while (p < end) 30 | { 31 | int ch = *p++; 32 | if(ch == 0) 33 | break; 34 | if ((ch & 0xc0) == 0xc0) 35 | { 36 | zlen = (ch & 0x7) + 1; 37 | zpos = ((ch >> 3) & 7) + 1; // + zlen; 38 | if (zpos > cpos) 39 | break; 40 | if (cpos + zlen >= maxclen) 41 | break; 42 | for (int z = 0; z < zlen; z++) 43 | cname[cpos + z] = cname[cpos - zpos + z]; 44 | cpos += zlen; 45 | } 46 | else if (ch >= 0x80) 47 | { 48 | if (p >= end) 49 | break; 50 | int ch2 = *p++; 51 | zlen = (ch2 & 0x7f) | ((ch & 0x38) << 4); 52 | if (p >= end) 53 | break; 54 | int ch3 = *p++; 55 | zpos = (ch3 & 0x7f) | ((ch & 7) << 7); 56 | if (zpos > cpos) 57 | break; 58 | if (cpos + zlen >= maxclen) 59 | break; 60 | for(int z = 0; z < zlen; z++) 61 | cname[cpos + z] = cname[cpos - zpos + z]; 62 | cpos += zlen; 63 | } 64 | #if 0 65 | if (ch == 0x80) 66 | { 67 | if (p >= end) 68 | break; 69 | zlen = *p++ & 0x7f; 70 | if (p >= end) 71 | break; 72 | zpos = *p++ & 0x7f; 73 | if (zpos > cpos) 74 | break; 75 | for(int z = 0; z < zlen; z++) 76 | cname[cpos + z] = cname[cpos - zpos + z]; 77 | cpos += zlen; 78 | } 79 | else if (ch > 0x80) 80 | { 81 | zlen = (ch & 0x7) + 1; 82 | zpos = ((ch >> 3) & 0xf) - 7; // + zlen; 83 | for(int z = 0; z < zlen; z++) 84 | cname[cpos + z] = cname[cpos - zpos + z]; 85 | cpos += zlen; 86 | } 87 | #endif 88 | else 89 | cname[cpos++] = ch; 90 | } 91 | if (p < end) 92 | { 93 | // decompression failed, assume it's containing UTF8 encoded characters 94 | cpos = min(maxclen, len); 95 | memcpy(cname, beg, cpos); 96 | } 97 | cname[cpos] = 0; 98 | if(demangleSymbols) 99 | if (cname[0] == '_' && cname[1] == 'D' && isdigit(cname[2])) 100 | d_demangle(cname, cname, maxclen, true); 101 | 102 | #if 1 103 | for(int i = 0; i < cpos; i++) 104 | if (cname[i] == '.') 105 | cname[i] = dotReplacementChar; 106 | #endif 107 | 108 | return cpos; 109 | } 110 | 111 | int pstrlen(const BYTE* &p) 112 | { 113 | int len = *p++; 114 | if(len == 0xff && *p == 0) 115 | { 116 | len = p[1] | (p[2] << 8); 117 | p += 3; 118 | } 119 | return len; 120 | } 121 | 122 | int pstrmemlen(const BYTE* p) 123 | { 124 | const BYTE* q = p; 125 | int len = pstrlen(p); 126 | return len + (p - q); 127 | } 128 | 129 | int dstrlen(const BYTE* &p, bool cstr) 130 | { 131 | if(cstr) 132 | return strlen((const char*)p); 133 | return pstrlen(p); 134 | } 135 | 136 | char* p2c(const BYTE* p, int idx) 137 | { 138 | static char cname[4][2560]; 139 | int len = pstrlen(p); 140 | 141 | #if 1 142 | memcpy(cname[idx], p, len); 143 | cname[idx][len] = 0; 144 | #else 145 | dsym2c(p, len, cname[idx], 2560); 146 | #endif 147 | return cname[idx]; 148 | } 149 | 150 | char* p2c(const p_string& p, int idx) 151 | { 152 | return p2c(&p.namelen, idx); 153 | } 154 | 155 | int c2p(const char* c, BYTE* p) 156 | { 157 | BYTE* q = p; 158 | int len = strlen(c); 159 | if(len > 255) 160 | { 161 | *p++ = 0xff; 162 | *p++ = 0; 163 | *p++ = len & 0xff; 164 | *p++ = len >> 8; 165 | } 166 | else 167 | *p++ = len; 168 | memcpy(p, c, len); 169 | return p + len - q; 170 | } 171 | 172 | int c2p(const char* c, p_string& p) 173 | { 174 | return c2p(c, &p.namelen); 175 | } 176 | 177 | int p2ccpy(char* p, const BYTE* s) 178 | { 179 | int len = pstrlen(s); 180 | memcpy(p, s, len); 181 | p[len] = 0; 182 | return len + 1; 183 | } 184 | 185 | int pstrcpy(BYTE* p, const BYTE* s) 186 | { 187 | const BYTE* src = s; 188 | int len = pstrlen(s); 189 | for(int i = 0; i <= s - src; i++) 190 | *p++ = src[i]; 191 | 192 | for(int i = 0; i < len; i++) 193 | if (s[i] == '.') 194 | { 195 | //p[i++] = ':'; 196 | p[i] = dotReplacementChar; 197 | } 198 | else 199 | p[i] = s[i]; 200 | return len + src - s; // *(BYTE*) memcpy (p, s, *s + 1) + 1; 201 | } 202 | 203 | int dmemcmp(const void* v1, const void* v2, int len) 204 | { 205 | const BYTE* p1 = (const BYTE*) v1; 206 | const BYTE* p2 = (const BYTE*) v2; 207 | for(int i = 0; i < len; i++) 208 | { 209 | int b1 = p1[i]; 210 | int b2 = p2[i]; 211 | if(b1 == '.') 212 | b1 = dotReplacementChar; 213 | if(b2 == '.') 214 | b2 = dotReplacementChar; 215 | if(b1 != b2) 216 | return b2 - b1; 217 | } 218 | return 0; 219 | } 220 | 221 | int pstrcpy(p_string& p, const p_string& s) 222 | { 223 | return *(BYTE*) memcpy (&p, &s, s.namelen + 1) + 1; 224 | } 225 | 226 | int pstrcmp(const BYTE* p1, const BYTE* p2) 227 | { 228 | int len1 = pstrlen(p1); 229 | int len2 = pstrlen(p2); 230 | if (len1 != len2) 231 | return len2 - len1; 232 | return dmemcmp(p1, p2, len1); 233 | } 234 | 235 | bool p2ccmp(const BYTE* pp, const char* cp) 236 | { 237 | int len = strlen(cp); 238 | int plen = pstrlen(pp); 239 | if (len != plen) 240 | return false; 241 | return dmemcmp(pp, cp, len) == 0; 242 | } 243 | 244 | bool p2ccmp(const p_string& pp, const char* cp) 245 | { 246 | return p2ccmp(&pp.namelen, cp); 247 | } 248 | 249 | bool dstrcmp(const BYTE* s1, bool cstr1, const BYTE* s2, bool cstr2) 250 | { 251 | int len1 = dstrlen(s1, cstr1); 252 | int len2 = dstrlen(s2, cstr2); 253 | if(len1 != len2) 254 | return false; 255 | return dmemcmp(s1, s2, len1) == 0; 256 | } 257 | 258 | int pstrcpy_v(bool v3, BYTE* d, const BYTE* s) 259 | { 260 | if (!v3) 261 | return pstrcpy(d, s); 262 | 263 | int len = pstrlen(s); 264 | int clen = dsym2c(s, len, (char*) d, kMaxNameLen) + 1; 265 | 266 | return clen; 267 | } 268 | 269 | int cstrcpy_v(bool v3, BYTE* d, const char* s) 270 | { 271 | // Process absent names as empty ones 272 | if (s == NULL) 273 | s = ""; 274 | 275 | int len = strlen(s); 276 | if(!v3) 277 | { 278 | assert(len < 256); 279 | *d++ = len; 280 | } 281 | len = (std::min)(len, kMaxNameLen-1); 282 | 283 | memcpy(d, s, len + 1); 284 | d[len] = '\0'; 285 | 286 | for(int i = 0; i < len; i++) 287 | if (d[i] == '.') 288 | d[i] = dotReplacementChar; 289 | 290 | return len + 1; 291 | } 292 | 293 | -------------------------------------------------------------------------------- /src/symutil.h: -------------------------------------------------------------------------------- 1 | // Convert DMD CodeView debug information to PDB files 2 | // Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved 3 | // 4 | // License for redistribution is given by the Artistic License 2.0 5 | // see file LICENSE for further details 6 | 7 | #ifndef __SYMUTIL_H__ 8 | #define __SYMUTIL_H__ 9 | 10 | #include 11 | 12 | struct p_string; 13 | 14 | static const int kMaxNameLen = 4096; 15 | 16 | int dsym2c(const BYTE* p, int len, char* cname, int maxclen); 17 | 18 | int pstrmemlen(const BYTE* p); 19 | int pstrlen(const BYTE* &p); 20 | char* p2c(const BYTE* p, int idx = 0); 21 | char* p2c(const p_string& p, int idx = 0); 22 | int c2p(const char* c, BYTE* p); // return byte len 23 | int c2p(const char* c, p_string& p); 24 | int p2ccpy(char* p, const BYTE* s); 25 | int pstrcpy(BYTE* p, const BYTE* s); 26 | int pstrcpy(p_string& p, const p_string& s); 27 | int pstrcmp(const BYTE* p1, const BYTE* p2); 28 | bool p2ccmp(const BYTE* pp, const char* cp); 29 | bool p2ccmp(const p_string& pp, const char* cp); 30 | int pstrcpy_v(bool v3, BYTE* d, const BYTE* s); 31 | int cstrcpy_v(bool v3, BYTE* d, const char* s); 32 | bool dstrcmp(const BYTE* s1, bool cstr1, const BYTE* s2, bool cstr2); 33 | 34 | extern char dotReplacementChar; 35 | extern bool demangleSymbols; 36 | extern bool useTypedefEnum; 37 | 38 | #endif //__SYMUTIL_H__ 39 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | 2 | PROJECT = cvtest 3 | 4 | SRC = cvtest.d 5 | 6 | DBGDIR = ..\bin\Debug 7 | RELDIR = ..\bin\Release 8 | 9 | DMD = c:\l\d\dmd2\windows\bin\dmd.exe 10 | # DMD = c:\l\dmd-1.045\windows\bin\dmd.exe 11 | 12 | CV2PDB_DBG = $(DBGDIR)\cv2pdb.exe 13 | CV2PDB_REL = $(RELDIR)\cv2pdb.exe 14 | 15 | DFLAGS = -L/DELEXECUTABLE 16 | LIBS = phobos.lib 17 | 18 | default: dbg_exe 19 | release: rel_exe 20 | 21 | dbg_exe: $(DBGDIR)\$(PROJECT).exe 22 | rel_exe: $(RELDIR)\$(PROJECT).exe 23 | 24 | ###################### 25 | $(DBGDIR)\$(PROJECT).exe : $(DBGDIR)\$(PROJECT)_cv.exe $(CV2PDB_DBG) 26 | $(CV2PDB_DBG) -D2.043 $(DBGDIR)\$(PROJECT)_cv.exe $@ 27 | 28 | $(DBGDIR)\$(PROJECT)_cv.exe : $(SRC) Makefile 29 | $(DMD) -of$@ -g -unittest $(DFLAGS) @<< 30 | $(SRC) $(LIBS) 31 | < 550 | ulong quirk_ulong; // written as int[] 551 | 552 | float f; 553 | double d; 554 | real r; 555 | 556 | ifloat iflt; 557 | idouble id; 558 | ireal ir; 559 | cfloat cf; 560 | cdouble cd; 561 | creal cr; 562 | 563 | return f + d + r + cf.im; 564 | } 565 | 566 | -------------------------------------------------------------------------------- /test/cvtest.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 25 | 38 | 39 | 45 | 58 | 59 | 60 | 61 | 62 | 63 | 66 | 67 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /test/cvtest.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {CCC0643D-7D3F-4D5E-AE0E-C871776E86AF} 15 | cvtest 16 | MakeFileProj 17 | 18 | 19 | 20 | Makefile 21 | v120 22 | 23 | 24 | Makefile 25 | v120 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | <_ProjectFileVersion>12.0.21005.1 39 | 40 | 41 | ..\bin\$(Configuration)\ 42 | $(OutDir) 43 | nmake -f Makefile 44 | 45 | 46 | ..\bin\Debug\cvtest.exe 47 | WIN32;_DEBUG;$(NMakePreprocessorDefinitions) 48 | 49 | 50 | ..\bin\$(Configuration)\ 51 | $(OutDir) 52 | nmake -f Makefile release 53 | 54 | 55 | ..\bin\Release\cvtest.exe 56 | WIN32;NDEBUG;$(NMakePreprocessorDefinitions) 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | {5e2bd27d-446a-4c99-9829-135f7c000d90} 67 | false 68 | 69 | 70 | 71 | 72 | 73 | --------------------------------------------------------------------------------