├── .gitattributes ├── .gitignore ├── README.md ├── cpp.cpp ├── cpp.h ├── doc ├── readme1.png ├── readme2.png ├── readme3.png ├── readme4.png └── readme5.png ├── dwarf.h ├── dwarf2cpp.sln ├── dwarf2cpp.vcxproj ├── dwarf2cpp.vcxproj.filters ├── elf.h └── main.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | 33 | # Visual Studio 2015/2017 cache/options directory 34 | .vs/ 35 | # Uncomment if you have tasks that create the project's static files in wwwroot 36 | #wwwroot/ 37 | 38 | # Visual Studio 2017 auto generated files 39 | Generated\ Files/ 40 | 41 | # MSTest test Results 42 | [Tt]est[Rr]esult*/ 43 | [Bb]uild[Ll]og.* 44 | 45 | # NUnit 46 | *.VisualState.xml 47 | TestResult.xml 48 | nunit-*.xml 49 | 50 | # Build Results of an ATL Project 51 | [Dd]ebugPS/ 52 | [Rr]eleasePS/ 53 | dlldata.c 54 | 55 | # Benchmark Results 56 | BenchmarkDotNet.Artifacts/ 57 | 58 | # .NET Core 59 | project.lock.json 60 | project.fragment.lock.json 61 | artifacts/ 62 | 63 | # StyleCop 64 | StyleCopReport.xml 65 | 66 | # Files built by Visual Studio 67 | *_i.c 68 | *_p.c 69 | *_h.h 70 | *.ilk 71 | *.meta 72 | *.obj 73 | *.iobj 74 | *.pch 75 | *.pdb 76 | *.ipdb 77 | *.pgc 78 | *.pgd 79 | *.rsp 80 | *.sbr 81 | *.tlb 82 | *.tli 83 | *.tlh 84 | *.tmp 85 | *.tmp_proj 86 | *_wpftmp.csproj 87 | *.log 88 | *.vspscc 89 | *.vssscc 90 | .builds 91 | *.pidb 92 | *.svclog 93 | *.scc 94 | 95 | # Chutzpah Test files 96 | _Chutzpah* 97 | 98 | # Visual C++ cache files 99 | ipch/ 100 | *.aps 101 | *.ncb 102 | *.opendb 103 | *.opensdf 104 | *.sdf 105 | *.cachefile 106 | *.VC.db 107 | *.VC.VC.opendb 108 | 109 | # Visual Studio profiler 110 | *.psess 111 | *.vsp 112 | *.vspx 113 | *.sap 114 | 115 | # Visual Studio Trace Files 116 | *.e2e 117 | 118 | # TFS 2012 Local Workspace 119 | $tf/ 120 | 121 | # Guidance Automation Toolkit 122 | *.gpState 123 | 124 | # ReSharper is a .NET coding add-in 125 | _ReSharper*/ 126 | *.[Rr]e[Ss]harper 127 | *.DotSettings.user 128 | 129 | # JustCode is a .NET coding add-in 130 | .JustCode 131 | 132 | # TeamCity is a build add-in 133 | _TeamCity* 134 | 135 | # DotCover is a Code Coverage Tool 136 | *.dotCover 137 | 138 | # AxoCover is a Code Coverage Tool 139 | .axoCover/* 140 | !.axoCover/settings.json 141 | 142 | # Visual Studio code coverage results 143 | *.coverage 144 | *.coveragexml 145 | 146 | # NCrunch 147 | _NCrunch_* 148 | .*crunch*.local.xml 149 | nCrunchTemp_* 150 | 151 | # MightyMoose 152 | *.mm.* 153 | AutoTest.Net/ 154 | 155 | # Web workbench (sass) 156 | .sass-cache/ 157 | 158 | # Installshield output folder 159 | [Ee]xpress/ 160 | 161 | # DocProject is a documentation generator add-in 162 | DocProject/buildhelp/ 163 | DocProject/Help/*.HxT 164 | DocProject/Help/*.HxC 165 | DocProject/Help/*.hhc 166 | DocProject/Help/*.hhk 167 | DocProject/Help/*.hhp 168 | DocProject/Help/Html2 169 | DocProject/Help/html 170 | 171 | # Click-Once directory 172 | publish/ 173 | 174 | # Publish Web Output 175 | *.[Pp]ublish.xml 176 | *.azurePubxml 177 | # Note: Comment the next line if you want to checkin your web deploy settings, 178 | # but database connection strings (with potential passwords) will be unencrypted 179 | *.pubxml 180 | *.publishproj 181 | 182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 183 | # checkin your Azure Web App publish settings, but sensitive information contained 184 | # in these scripts will be unencrypted 185 | PublishScripts/ 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # NuGet Symbol Packages 190 | *.snupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/[Pp]ackages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/[Pp]ackages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/[Pp]ackages/repositories.config 197 | # NuGet v3's project.json files produces more ignorable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | *.appx 215 | *.appxbundle 216 | *.appxupload 217 | 218 | # Visual Studio cache files 219 | # files ending in .cache can be ignored 220 | *.[Cc]ache 221 | # but keep track of directories ending in .cache 222 | !?*.[Cc]ache/ 223 | 224 | # Others 225 | ClientBin/ 226 | ~$* 227 | *~ 228 | *.dbmdl 229 | *.dbproj.schemaview 230 | *.jfm 231 | *.pfx 232 | *.publishsettings 233 | orleans.codegen.cs 234 | 235 | # Including strong name files can present a security risk 236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 237 | #*.snk 238 | 239 | # Since there are multiple workflows, uncomment next line to ignore bower_components 240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 241 | #bower_components/ 242 | 243 | # RIA/Silverlight projects 244 | Generated_Code/ 245 | 246 | # Backup & report files from converting an old project file 247 | # to a newer Visual Studio version. Backup files are not needed, 248 | # because we have git ;-) 249 | _UpgradeReport_Files/ 250 | Backup*/ 251 | UpgradeLog*.XML 252 | UpgradeLog*.htm 253 | ServiceFabricBackup/ 254 | *.rptproj.bak 255 | 256 | # SQL Server files 257 | *.mdf 258 | *.ldf 259 | *.ndf 260 | 261 | # Business Intelligence projects 262 | *.rdl.data 263 | *.bim.layout 264 | *.bim_*.settings 265 | *.rptproj.rsuser 266 | *- [Bb]ackup.rdl 267 | *- [Bb]ackup ([0-9]).rdl 268 | *- [Bb]ackup ([0-9][0-9]).rdl 269 | 270 | # Microsoft Fakes 271 | FakesAssemblies/ 272 | 273 | # GhostDoc plugin setting file 274 | *.GhostDoc.xml 275 | 276 | # Node.js Tools for Visual Studio 277 | .ntvs_analysis.dat 278 | node_modules/ 279 | 280 | # Visual Studio 6 build log 281 | *.plg 282 | 283 | # Visual Studio 6 workspace options file 284 | *.opt 285 | 286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 287 | *.vbw 288 | 289 | # Visual Studio LightSwitch build output 290 | **/*.HTMLClient/GeneratedArtifacts 291 | **/*.DesktopClient/GeneratedArtifacts 292 | **/*.DesktopClient/ModelManifest.xml 293 | **/*.Server/GeneratedArtifacts 294 | **/*.Server/ModelManifest.xml 295 | _Pvt_Extensions 296 | 297 | # Paket dependency manager 298 | .paket/paket.exe 299 | paket-files/ 300 | 301 | # FAKE - F# Make 302 | .fake/ 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb 347 | 348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 349 | MigrationBackup/ 350 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dwarf2cpp 2 | This tool reads DWARF 1.0/1.1 data from an ELF file and converts it into C/C++ files containing all struct, enum, union, and function definitions, as well as variable declarations, that it finds in the DWARF data. 3 | 4 | ![dwarf2cpp screenshot](doc/readme1.png) 5 | 6 | Below is an example of a struct that can be reconstructed from a DWARF entry. This tool supports inheritance, pointers/references to user types, and unnamed unions, among other things. 7 | 8 | ![zScene example struct](doc/readme2.png) 9 | 10 | If you see a variable or struct member that has the type "type_" followed by a number, that type is either a function pointer type or an array. At the top of the file, along with typedefs for all named structs, enums, unions, you'll also find typedefs for function pointer types and arrays. 11 | 12 | ![Function pointer typedefs](doc/readme4.png) 13 | ![Array typedefs](doc/readme3.png) 14 | 15 | Below is an example of a function definition. This tool reads argument names and types, as well as any local variables declared within the function. It also prints the mangled version of the function name and the address of the first instruction in the function. **Note that the function's signature might be missing some arguments.** DWARF data sometimes doesn't include unused arguments in function entries. You can use the mangled name to figure out which arguments are missing from the signature. 16 | 17 | ![Example function definition](doc/readme5.png) 18 | 19 | This tool was built specifically as a reverse engineering tool for the PS2 version of SpongeBob SquarePants: Battle for Bikini Bottom, but it may work with other games and programs as well, provided that they contain DWARF 1.0/1.1 debugging information (DWARF 2.0 and up is *not* supported) and the DWARF structure is the same as what is expected from this tool. 20 | 21 | Please note that this tool is not meant to generate *compilable* code. The code that's generated may be syntactically correct, but it is only meant to be a starting or reference point for reverse engineering a piece of software. The C++ generation code is overall fairly simple and only generates definitions in the order that they are read in from the DWARF data. Struct definitions, for example, will likely run into "incomplete type" errors if they contain values of types that haven't been defined yet. This tool will not decompile functions for you either, so function definitions will only contain local variable declarations and no other statements. 22 | 23 | ## Compiling 24 | This tool makes use of the std::experimental::filesystem library (C++17). A Visual Studio solution is included. 25 | 26 | If using gcc you can compile with: 27 | ``` 28 | g++ *.cpp -o dwarf2cpp -lstdc++fs 29 | ``` 30 | 31 | [More information](https://www.codingame.com/playgrounds/5659/c17-filesystem) (See Compiler/Library support) 32 | 33 | ## Usage 34 | ``` 35 | dwarf2cpp 36 | ``` 37 | 38 | * `` is the path to your ELF file. It can have any extension. 39 | * `` is the path to a directory that you want the C/C++ files to be written to. This tool takes the path of every compile unit and replaces the root of the path with the directory path you specify here. 40 | * Example: 41 | * `` is `C:\Users\your-username\Desktop\Code\` 42 | * A compile unit's path is `C:\SB\Core\x\xEnt.cpp` 43 | * The output file will be `C:\Users\your-username\Desktop\Code\SB\Core\x\xEnt.cpp` 44 | 45 | ## Customization 46 | You can edit [cpp.h](cpp.h) and [cpp.cpp](cpp.cpp) to customize how the C/C++ output is generated. Currently, there are no customization options that can be passed as command line arguments to this tool. 47 | 48 | ## DWARFv1 Documentation 49 | Useful References: 50 | - http://www.dwarfstd.org/doc/dwarf_1_1_0.pdf -------------------------------------------------------------------------------- /cpp.cpp: -------------------------------------------------------------------------------- 1 | #include "cpp.h" 2 | 3 | namespace Cpp 4 | { 5 | static inline std::string toHexString(int x) 6 | { 7 | std::stringstream ss; 8 | ss << std::hex << std::showbase << x; 9 | return ss.str(); 10 | } 11 | 12 | std::string File::toString(bool justUserTypes, bool includeComments) 13 | { 14 | std::stringstream ss; 15 | 16 | // Write class/enum declarations 17 | for (UserType *ut : userTypes) 18 | { 19 | if (ut->type == UserType::CLASS || 20 | ut->type == UserType::UNION || 21 | ut->type == UserType::STRUCT || 22 | ut->type == UserType::ENUM) 23 | ss << ut->toDeclarationString() << "\n"; 24 | } 25 | 26 | ss << "\n"; 27 | 28 | // Write function type definitions 29 | for (UserType *ut : userTypes) 30 | { 31 | if (ut->type == UserType::FUNCTION) 32 | ss << ut->toDeclarationString() << "\n"; 33 | } 34 | 35 | ss << "\n"; 36 | 37 | // Write array type declarations 38 | for (UserType *ut : userTypes) 39 | { 40 | if (ut->type == UserType::ARRAY) 41 | ss << ut->toDeclarationString() << "\n"; 42 | } 43 | 44 | ss << "\n"; 45 | 46 | // Write class/enum definitions 47 | for (UserType *ut : userTypes) 48 | { 49 | if (ut->type == UserType::CLASS || 50 | ut->type == UserType::UNION || 51 | ut->type == UserType::STRUCT || 52 | ut->type == UserType::ENUM) 53 | { 54 | ss << ut->toDefinitionString(includeComments) << "\n\n"; 55 | } 56 | } 57 | 58 | if (!justUserTypes) 59 | { 60 | // Write variables 61 | for (Variable &var : variables) 62 | { 63 | if (includeComments) 64 | { 65 | std::string globallocal = (var.isGlobal) ? "GLOBAL" : "LOCAL "; 66 | ss << StarCommentToString(globallocal, false) << " "; 67 | } 68 | 69 | ss << var.toString() << ";\n"; 70 | } 71 | 72 | ss << "\n"; 73 | 74 | // Write function declarations 75 | for (Function &fun : functions) 76 | { 77 | if (includeComments) 78 | { 79 | std::string globallocal = (fun.isGlobal) ? "GLOBAL" : "LOCAL "; 80 | ss << StarCommentToString(globallocal, false) << " "; 81 | } 82 | ss << fun.toDeclarationString() << "\n"; 83 | } 84 | 85 | ss << "\n"; 86 | 87 | // Write function definitions 88 | for (Function &fun : functions) 89 | ss << fun.toDefinitionString() << "\n\n"; 90 | } 91 | 92 | return ss.str(); 93 | } 94 | 95 | std::string Type::toString(std::string varName) { 96 | std::stringstream result; 97 | 98 | // Add prefix modifiers. 99 | for (Modifier mod : modifiers) 100 | if (mod == Modifier::CONST || mod == Modifier::VOLATILE) 101 | result << ModifierToString(mod) << " "; 102 | 103 | if (isFundamentalType) { 104 | result << FundamentalTypeToString(fundamentalType); 105 | } else if (userType->type == UserType::ARRAY) { 106 | return userType->arrayData->toNameString(varName); 107 | } 108 | else if (userType->type == UserType::FUNCTION) { 109 | return userType->functionData->toNameString(varName); 110 | } 111 | else { 112 | result << userType->name; 113 | } 114 | 115 | for (Modifier mod : modifiers) 116 | if (mod == Modifier::POINTER_TO || mod == Modifier::REFERENCE_TO) 117 | result << ModifierToString(mod); 118 | 119 | if (!varName.empty()) 120 | result << " " << varName; 121 | 122 | return result.str(); 123 | } 124 | 125 | std::string Type::toString() 126 | { 127 | return toString(""); 128 | } 129 | 130 | std::string Variable::toString() 131 | { 132 | std::stringstream ss; 133 | ss << type.toString(name); 134 | return ss.str(); 135 | } 136 | 137 | std::string UserType::toDeclarationString() 138 | { 139 | std::stringstream ss; 140 | ss << "typedef " << toNameString(false, false) << ";"; 141 | return ss.str(); 142 | } 143 | 144 | std::string UserType::toDefinitionString(bool includeComments) 145 | { 146 | std::stringstream ss; 147 | ss << toNameString(includeComments, true) << "\n"; 148 | 149 | switch (type) 150 | { 151 | case UNION: 152 | case STRUCT: 153 | case CLASS: 154 | ss << classData->toBodyString(includeComments); 155 | break; 156 | case ENUM: 157 | ss << enumData->toBodyString(); 158 | break; 159 | } 160 | 161 | ss << ";"; 162 | 163 | return ss.str(); 164 | } 165 | 166 | std::string UserType::toNameString(bool includeSize, bool includeInheritances) 167 | { 168 | switch (type) 169 | { 170 | case UNION: 171 | case STRUCT: 172 | case CLASS: 173 | return classData->toNameString(name, includeSize, includeInheritances); 174 | case ENUM: 175 | return enumData->toNameString(name); 176 | case ARRAY: 177 | return arrayData->toNameString(name); 178 | case FUNCTION: 179 | return functionData->toNameString(name); 180 | } 181 | 182 | return ""; 183 | } 184 | 185 | std::string ClassType::toNameString(std::string name, bool includeSize, bool includeInheritances) 186 | { 187 | std::stringstream ss; 188 | ss << std::string((parent->type == UserType::STRUCT) ? "struct " : ((parent->type == UserType::UNION) ? "union " : "class ")) << name; 189 | 190 | if (includeInheritances) 191 | { 192 | for (size_t i = 0; i < inheritances.size(); i++) 193 | { 194 | std::string type = inheritances[i].type.toString(); 195 | 196 | if (i == 0) 197 | ss << " : " << type; 198 | else 199 | ss << ", " << type; 200 | } 201 | } 202 | 203 | if (includeSize) 204 | ss << " " + StarCommentToString(toHexString(size), false); 205 | 206 | return ss.str(); 207 | } 208 | 209 | std::string ClassType::toBodyString(bool includeOffsets) 210 | { 211 | std::stringstream ss; 212 | ss << "{\n"; 213 | 214 | bool includeUnions = (parent->type != UserType::UNION); 215 | int unionOffset = -1; 216 | 217 | size_t size = members.size(); 218 | 219 | for (size_t i = 0; i < size; i++) 220 | { 221 | ss << "\t"; 222 | 223 | Member &m = members[i]; 224 | int offset = m.offset; 225 | 226 | if (includeUnions && offset != unionOffset && 227 | i < size - 1 && members[i + 1].offset == offset) 228 | { 229 | unionOffset = offset; 230 | 231 | if (m.bit_size == -1) { 232 | ss << "union"; 233 | } 234 | else { 235 | ss << "struct"; 236 | } 237 | 238 | ss << "\n\t{\n\t"; 239 | } 240 | 241 | if (includeUnions && unionOffset != -1) 242 | ss << "\t"; 243 | 244 | ss << m.toString(includeOffsets) << ";\n"; 245 | 246 | if (includeUnions && unionOffset != -1 && 247 | (i == size - 1 || members[i+1].offset != offset)) 248 | { 249 | unionOffset = -1; 250 | ss << "\t};\n"; 251 | } 252 | } 253 | 254 | if (functions.size() > 0) { 255 | ss << "\n"; 256 | for (Function& fun : functions) { 257 | ss << "\t" << fun.toDeclarationString() << "\n"; 258 | } 259 | } 260 | 261 | ss << "}"; 262 | 263 | return ss.str(); 264 | } 265 | 266 | std::string ClassType::Member::toString(bool includeOffset) 267 | { 268 | std::stringstream ss; 269 | 270 | if (includeOffset) 271 | ss << StarCommentToString(toHexString(offset), false) << " "; 272 | 273 | ss << type.toString(name); 274 | if (bit_size != -1) 275 | ss << " : " << bit_size; 276 | 277 | return ss.str(); 278 | } 279 | 280 | std::string EnumType::toNameString(std::string name) 281 | { 282 | std::stringstream ss; 283 | ss << "enum " << name; 284 | if (baseType != Cpp::FundamentalType::INT) 285 | ss << " : " << FundamentalTypeToString(baseType); 286 | return ss.str(); 287 | } 288 | 289 | std::string EnumType::toBodyString() 290 | { 291 | std::stringstream ss; 292 | 293 | ss << "{\n"; 294 | 295 | int lastValue = -1; 296 | size_t size = elements.size(); 297 | 298 | for (size_t i = 0; i < size; i++) 299 | { 300 | ss << "\t" << elements[i].toString(lastValue); 301 | 302 | lastValue = elements[i].constValue; 303 | 304 | if (i != size - 1) 305 | ss << ","; 306 | 307 | ss << "\n"; 308 | } 309 | 310 | ss << "}"; 311 | 312 | return ss.str(); 313 | } 314 | 315 | std::string EnumType::Element::toString(int lastValue) 316 | { 317 | std::stringstream ss; 318 | ss << name; 319 | 320 | if (constValue != lastValue + 1) 321 | ss << " = " << toHexString(constValue); 322 | 323 | return ss.str(); 324 | } 325 | 326 | std::string ArrayType::toNameString(std::string name) 327 | { 328 | std::stringstream ss; 329 | ss << type.toString(name); 330 | 331 | for (Dimension &d : dimensions) 332 | ss << "[" << std::to_string(d.size) << "]"; 333 | 334 | return ss.str(); 335 | } 336 | 337 | std::string FunctionType::toNameString(std::string name) 338 | { 339 | std::stringstream ss; 340 | 341 | // This isn't really a function pointer, but we'll print it as if it is 342 | // DWARF is weird 343 | ss << returnType.toString() << "(*" << name << ")" << toParametersString(); 344 | return ss.str(); 345 | } 346 | 347 | std::string FunctionType::toParametersString() 348 | { 349 | std::stringstream ss; 350 | ss << "("; 351 | 352 | size_t size = parameters.size(); 353 | 354 | for (size_t i = 0; i < size; i++) 355 | { 356 | ss << parameters[i].toString(); 357 | 358 | if (i != size - 1) 359 | ss << ", "; 360 | } 361 | 362 | ss << ")"; 363 | 364 | return ss.str(); 365 | } 366 | 367 | std::string FunctionType::Parameter::toString() 368 | { 369 | return type.toString(name); 370 | } 371 | 372 | std::string Function::toNameString(bool skipNamespace) 373 | { 374 | std::stringstream ss; 375 | ss << returnType.toString() << " "; 376 | if (typeOwner != nullptr && !skipNamespace) 377 | ss << typeOwner->name << "::"; 378 | ss << name << toParametersString(); 379 | return ss.str(); 380 | } 381 | 382 | std::string Function::toNameString() 383 | { 384 | return toNameString(false); 385 | } 386 | 387 | std::string Function::toDeclarationString() 388 | { 389 | std::stringstream ss; 390 | ss << toNameString(true) << ";"; 391 | return ss.str(); 392 | } 393 | 394 | std::string Function::toDefinitionString() 395 | { 396 | std::stringstream ss; 397 | ss << CommentToString(mangledName) << 398 | CommentToString("Start address: " + toHexString(startAddress)) << 399 | toNameString() << "\n{\n"; 400 | 401 | for (Variable &v : variables) 402 | ss << "\t" << v.toString() << ";\n"; 403 | 404 | // Save line numbers. 405 | if (dwarf != nullptr) { 406 | std::multimap::iterator lines = dwarf->lineEntryMap.find(startAddress); 407 | if (lines != dwarf->lineEntryMap.end()) { 408 | std::pair::iterator, std::multimap::iterator> ret; 409 | ret = dwarf->lineEntryMap.equal_range(startAddress); 410 | for (std::multimap::iterator it = ret.first; it != ret.second; ++it) { 411 | ss << "\t// "; 412 | if (it->second.lineNumber != 0) { 413 | ss << "Line " << it->second.lineNumber; 414 | } 415 | else { 416 | ss << "Func End"; 417 | } 418 | 419 | if (it->second.charOffset != (short)-1) 420 | ss << ", Character " << it->second.charOffset; 421 | ss << ", Address: " << toHexString(startAddress + it->second.hexAddressOffset) << ", Func Offset: " << toHexString(it->second.hexAddressOffset) << "\n"; 422 | } 423 | } 424 | } 425 | 426 | ss << "}"; 427 | 428 | return ss.str(); 429 | } 430 | 431 | std::string FundamentalTypeToString(FundamentalType ft) 432 | { 433 | switch (ft) 434 | { 435 | case FundamentalType::CHAR: 436 | case FundamentalType::SIGNED_CHAR: 437 | return "char"; 438 | case FundamentalType::UNSIGNED_CHAR: 439 | return "unsigned char"; 440 | case FundamentalType::SHORT: 441 | case FundamentalType::SIGNED_SHORT: 442 | return "short"; 443 | case FundamentalType::UNSIGNED_SHORT: 444 | return "unsigned short"; 445 | case FundamentalType::INT: 446 | case FundamentalType::SIGNED_INT: 447 | return "int"; 448 | case FundamentalType::UNSIGNED_INT: 449 | return "unsigned int"; 450 | case FundamentalType::LONG: 451 | case FundamentalType::SIGNED_LONG: 452 | return "long"; 453 | case FundamentalType::UNSIGNED_LONG: 454 | return "unsigned long"; 455 | case FundamentalType::FLOAT: 456 | return "float"; 457 | case FundamentalType::DOUBLE: 458 | return "double"; 459 | case FundamentalType::LONG_DOUBLE: 460 | return "long double"; 461 | case FundamentalType::VOID: 462 | return "void"; 463 | case FundamentalType::BOOL: 464 | return "bool"; 465 | case FundamentalType::LONG_LONG: 466 | case FundamentalType::SIGNED_LONG_LONG: 467 | return "long long"; 468 | case FundamentalType::UNSIGNED_LONG_LONG: 469 | return "unsigned long long"; 470 | } 471 | 472 | std::stringstream ss; 473 | ss << ""; 474 | return ss.str(); 475 | } 476 | 477 | int GetFundamentalTypeSize(FundamentalType ft) 478 | { 479 | switch (ft) 480 | { 481 | case FundamentalType::CHAR: 482 | case FundamentalType::SIGNED_CHAR: 483 | case FundamentalType::UNSIGNED_CHAR: 484 | return 1; 485 | case FundamentalType::SHORT: 486 | case FundamentalType::SIGNED_SHORT: 487 | case FundamentalType::UNSIGNED_SHORT: 488 | return 2; 489 | case FundamentalType::INT: 490 | case FundamentalType::SIGNED_INT: 491 | case FundamentalType::UNSIGNED_INT: 492 | return 4; 493 | case FundamentalType::LONG: 494 | case FundamentalType::SIGNED_LONG: 495 | case FundamentalType::UNSIGNED_LONG: 496 | return 8; // Confirmed 8 bytes. 497 | case FundamentalType::FLOAT: 498 | return 4; 499 | case FundamentalType::DOUBLE: 500 | return 8; 501 | case FundamentalType::LONG_DOUBLE: 502 | return 8; // TODO: UNSURE 503 | case FundamentalType::VOID: 504 | return 4; // TODO: UNSURE 505 | case FundamentalType::BOOL: 506 | return 1; // TODO: UNSURE 507 | case FundamentalType::LONG_LONG: 508 | case FundamentalType::SIGNED_LONG_LONG: 509 | case FundamentalType::UNSIGNED_LONG_LONG: 510 | return 8; // TODO: UNSURE 511 | } 512 | 513 | return -1; 514 | } 515 | 516 | int Type::size() { 517 | if (modifiers.size() > 0) 518 | for (Cpp::Type::Modifier modifier : modifiers) 519 | if (modifier == Cpp::Type::Modifier::POINTER_TO || modifier == Cpp::Type::Modifier::REFERENCE_TO) 520 | return 4; 521 | 522 | if (isFundamentalType) { 523 | return GetFundamentalTypeSize(fundamentalType); 524 | } 525 | else { 526 | switch (userType->type) { 527 | case Cpp::UserType::STRUCT: 528 | case Cpp::UserType::CLASS: 529 | case Cpp::UserType::UNION: 530 | return userType->classData->size; 531 | break; 532 | case Cpp::UserType::ARRAY: 533 | int amount; 534 | amount = 1; 535 | if (userType->arrayData->dimensions.size() > 0) 536 | for (auto dimension : userType->arrayData->dimensions) 537 | amount *= dimension.size; 538 | return amount * userType->arrayData->type.size(); 539 | break; 540 | case Cpp::UserType::FUNCTION: 541 | return 4; 542 | break; 543 | case Cpp::UserType::ENUM: 544 | return GetFundamentalTypeSize(userType->enumData->baseType); 545 | break; 546 | } 547 | } 548 | } 549 | 550 | std::string Type::ModifierToString(Modifier m) 551 | { 552 | switch (m) 553 | { 554 | case CONST: 555 | return "const"; 556 | case POINTER_TO: 557 | return "*"; 558 | case REFERENCE_TO: 559 | return "&"; 560 | case VOLATILE: 561 | return "volatile"; 562 | } 563 | 564 | std::stringstream ss; 565 | ss << ""; 566 | return ss.str(); 567 | } 568 | 569 | std::string CommentToString(std::string comment) 570 | { 571 | return "// " + comment + "\n"; 572 | } 573 | 574 | std::string StarCommentToString(std::string comment, bool multiline) 575 | { 576 | if (multiline) 577 | return "/*\n" + comment + "\n*/\n"; 578 | else 579 | return "/* " + comment + " */"; 580 | } 581 | } -------------------------------------------------------------------------------- /cpp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dwarf.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Cpp 10 | { 11 | struct File; 12 | struct Type; 13 | struct Variable; 14 | struct UserType; 15 | struct ClassType; 16 | struct EnumType; 17 | struct ArrayType; 18 | struct FunctionType; 19 | struct Function; 20 | 21 | enum FundamentalType 22 | { 23 | CHAR = 0x01, 24 | SIGNED_CHAR = 0x02, 25 | UNSIGNED_CHAR = 0x03, 26 | SHORT = 0x04, 27 | SIGNED_SHORT = 0x05, 28 | UNSIGNED_SHORT = 0x06, 29 | INT = 0x07, 30 | SIGNED_INT = 0x08, 31 | UNSIGNED_INT = 0x09, 32 | LONG = 0x0a, 33 | SIGNED_LONG = 0x0b, 34 | UNSIGNED_LONG = 0x0c, 35 | FLOAT = 0x0e, 36 | DOUBLE = 0x0f, 37 | LONG_DOUBLE = 0x10, 38 | VOID = 0x14, 39 | BOOL = 0x15, 40 | LONG_LONG = 0x8008, 41 | SIGNED_LONG_LONG = 0x8108, 42 | UNSIGNED_LONG_LONG = 0x8208 43 | }; 44 | 45 | struct File 46 | { 47 | std::string filename; 48 | std::vector variables; 49 | std::vector userTypes; 50 | std::vector functions; 51 | 52 | std::string toString(bool justUserTypes, bool includeComments); 53 | }; 54 | 55 | struct Type 56 | { 57 | enum Modifier 58 | { 59 | CONST = 0x0, 60 | POINTER_TO = 0x1, 61 | REFERENCE_TO = 0x2, 62 | VOLATILE = 0x3 63 | }; 64 | 65 | bool isFundamentalType; 66 | std::vector modifiers; 67 | 68 | union 69 | { 70 | FundamentalType fundamentalType; 71 | UserType *userType; 72 | }; 73 | 74 | int size(); 75 | std::string toString(std::string varName); 76 | std::string toString(); 77 | static std::string ModifierToString(Modifier m); 78 | }; 79 | 80 | struct Variable 81 | { 82 | std::string name; 83 | bool isGlobal; 84 | Type type; 85 | 86 | std::string toString(); 87 | }; 88 | 89 | struct UserType 90 | { 91 | enum { CLASS, UNION, STRUCT, ENUM, ARRAY, FUNCTION } type; 92 | std::string name; 93 | int index; 94 | 95 | union 96 | { 97 | ClassType *classData; 98 | EnumType *enumData; 99 | ArrayType *arrayData; 100 | FunctionType *functionData; 101 | }; 102 | 103 | std::string toDeclarationString(); 104 | std::string toDefinitionString(bool includeComments); 105 | std::string toNameString(bool includeSize, bool includeInheritances); 106 | }; 107 | 108 | struct ClassType 109 | { 110 | struct Member 111 | { 112 | int offset; 113 | std::string name; 114 | Type type; 115 | int bit_offset; 116 | int bit_size; 117 | 118 | std::string toString(bool includeOffset); 119 | }; 120 | 121 | struct Inheritance 122 | { 123 | int offset; 124 | Type type; 125 | }; 126 | 127 | UserType* parent; 128 | int size; 129 | std::vector members; 130 | std::vector inheritances; 131 | std::vector functions; 132 | 133 | std::string toNameString(std::string name, bool includeSize, bool includeInheritances); 134 | std::string toBodyString(bool includeOffsets); 135 | bool isUnion(); 136 | }; 137 | 138 | struct EnumType 139 | { 140 | struct Element 141 | { 142 | std::string name; 143 | long constValue; 144 | 145 | std::string toString(int lastValue); 146 | }; 147 | 148 | FundamentalType baseType; 149 | std::vector elements; 150 | 151 | std::string toNameString(std::string name); 152 | std::string toBodyString(); 153 | }; 154 | 155 | struct ArrayType 156 | { 157 | struct Dimension 158 | { 159 | int size; 160 | }; 161 | 162 | Type type; 163 | std::vector dimensions; 164 | 165 | std::string toNameString(std::string name); 166 | }; 167 | 168 | struct FunctionType 169 | { 170 | struct Parameter 171 | { 172 | std::string name; 173 | Type type; 174 | 175 | std::string toString(); 176 | }; 177 | 178 | Type returnType; 179 | std::vector parameters; 180 | 181 | std::string toNameString(std::string name); 182 | std::string toParametersString(); 183 | }; 184 | 185 | struct Function : FunctionType 186 | { 187 | 188 | bool isGlobal; 189 | std::string name; 190 | std::string mangledName; 191 | unsigned int startAddress; 192 | std::vector variables; 193 | UserType* typeOwner; 194 | Dwarf* dwarf; 195 | 196 | std::string toNameString(); 197 | std::string toNameString(bool skipNamespace); 198 | std::string toDeclarationString(); 199 | std::string toDefinitionString(); 200 | }; 201 | 202 | std::string FundamentalTypeToString(FundamentalType ft); 203 | int GetFundamentalTypeSize(FundamentalType ft); 204 | std::string CommentToString(std::string comment); 205 | std::string StarCommentToString(std::string comment, bool multiline); 206 | std::string IndentToString(int level); 207 | } -------------------------------------------------------------------------------- /doc/readme1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seilweiss/dwarf2cpp/330b00677ddc1ad95203e2dde8e81997ff67d0d1/doc/readme1.png -------------------------------------------------------------------------------- /doc/readme2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seilweiss/dwarf2cpp/330b00677ddc1ad95203e2dde8e81997ff67d0d1/doc/readme2.png -------------------------------------------------------------------------------- /doc/readme3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seilweiss/dwarf2cpp/330b00677ddc1ad95203e2dde8e81997ff67d0d1/doc/readme3.png -------------------------------------------------------------------------------- /doc/readme4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seilweiss/dwarf2cpp/330b00677ddc1ad95203e2dde8e81997ff67d0d1/doc/readme4.png -------------------------------------------------------------------------------- /doc/readme5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seilweiss/dwarf2cpp/330b00677ddc1ad95203e2dde8e81997ff67d0d1/doc/readme5.png -------------------------------------------------------------------------------- /dwarf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "elf.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define DW_TAG_padding 0x0000 11 | #define DW_TAG_array_type 0x0001 12 | #define DW_TAG_class_type 0x0002 13 | #define DW_TAG_entry_point 0x0003 14 | #define DW_TAG_enumeration_type 0x0004 15 | #define DW_TAG_formal_parameter 0x0005 16 | #define DW_TAG_global_subroutine 0x0006 17 | #define DW_TAG_global_variable 0x0007 18 | #define DW_TAG_label 0x000a 19 | #define DW_TAG_lexical_block 0x000b 20 | #define DW_TAG_local_variable 0x000c 21 | #define DW_TAG_member 0x000d 22 | #define DW_TAG_pointer_type 0x000f 23 | #define DW_TAG_reference_type 0x0010 24 | #define DW_TAG_compile_unit 0x0011 25 | #define DW_TAG_source_file 0x0011 26 | #define DW_TAG_string_type 0x0012 27 | #define DW_TAG_structure_type 0x0013 28 | #define DW_TAG_subroutine 0x0014 29 | #define DW_TAG_subroutine_type 0x0015 30 | #define DW_TAG_typedef 0x0016 31 | #define DW_TAG_union_type 0x0017 32 | #define DW_TAG_unspecified_parameters 0x0018 33 | #define DW_TAG_variant 0x0019 34 | #define DW_TAG_common_block 0x001a 35 | #define DW_TAG_common_inclusion 0x001b 36 | #define DW_TAG_inheritance 0x001c 37 | #define DW_TAG_inlined_subroutine 0x001d 38 | #define DW_TAG_module 0x001e 39 | #define DW_TAG_ptr_to_member_type 0x001f 40 | #define DW_TAG_set_type 0x0020 41 | #define DW_TAG_subrange_type 0x0021 42 | #define DW_TAG_with_stmt 0x0022 43 | #define DW_TAG_lo_user 0x4080 44 | #define DW_TAG_hi_user 0xffff 45 | 46 | #define DW_FORM_ADDR 0x1 47 | #define DW_FORM_REF 0x2 48 | #define DW_FORM_BLOCK2 0x3 49 | #define DW_FORM_BLOCK4 0x4 50 | #define DW_FORM_DATA2 0x5 51 | #define DW_FORM_DATA4 0x6 52 | #define DW_FORM_DATA8 0x7 53 | #define DW_FORM_STRING 0x8 54 | 55 | #define DW_AT_sibling (0x0010|DW_FORM_REF) 56 | #define DW_AT_location (0x0020|DW_FORM_BLOCK2) 57 | #define DW_AT_name (0x0030|DW_FORM_STRING) 58 | #define DW_AT_fund_type (0x0050|DW_FORM_DATA2) 59 | #define DW_AT_mod_fund_type (0x0060|DW_FORM_BLOCK2) 60 | #define DW_AT_user_def_type (0x0070|DW_FORM_REF) 61 | #define DW_AT_mod_u_d_type (0x0080|DW_FORM_BLOCK2) 62 | #define DW_AT_ordering (0x0090|DW_FORM_DATA2) 63 | #define DW_AT_subscr_data (0x00a0|DW_FORM_BLOCK2) 64 | #define DW_AT_byte_size (0x00b0|DW_FORM_DATA4) 65 | #define DW_AT_bit_offset (0x00c0|DW_FORM_DATA2) 66 | #define DW_AT_bit_size (0x00d0|DW_FORM_DATA4) 67 | #define DW_AT_element_list (0x00f0|DW_FORM_BLOCK4) 68 | #define DW_AT_stmt_list (0x0100|DW_FORM_DATA4) 69 | #define DW_AT_low_pc (0x0110|DW_FORM_ADDR) 70 | #define DW_AT_high_pc (0x0120|DW_FORM_ADDR) 71 | #define DW_AT_language (0x0130|DW_FORM_DATA4) 72 | #define DW_AT_member (0x0140|DW_FORM_REF) 73 | #define DW_AT_discr (0x0150|DW_FORM_REF) 74 | #define DW_AT_discr_value (0x0160|DW_FORM_BLOCK2) 75 | #define DW_AT_string_length (0x0190|DW_FORM_BLOCK2) 76 | #define DW_AT_common_reference (0x01a0|DW_FORM_REF) 77 | #define DW_AT_comp_dir (0x01b0|DW_FORM_STRING) 78 | #define DW_AT_const_value_string (0x01c0|DW_FORM_STRING) 79 | #define DW_AT_const_value_data2 (0x01c0|DW_FORM_DATA2) 80 | #define DW_AT_const_value_data4 (0x01c0|DW_FORM_DATA4) 81 | #define DW_AT_const_value_data8 (0x01c0|DW_FORM_DATA8) 82 | #define DW_AT_const_value_block2 (0x01c0|DW_FORM_BLOCK2) 83 | #define DW_AT_const_value_block4 (0x01c0|DW_FORM_BLOCK4) 84 | #define DW_AT_containing_type (0x01d0|DW_FORM_REF) 85 | #define DW_AT_default_value_addr (0x01e0|DW_FORM_ADDR) 86 | #define DW_AT_default_value_data2 (0x01e0|DW_FORM_DATA2) 87 | #define DW_AT_default_value_data8 (0x01e0|DW_FORM_DATA8) 88 | #define DW_AT_default_value_string (0x01e0|DW_FORM_STRING) 89 | #define DW_AT_friends (0x01f0|DW_FORM_BLOCK2) 90 | #define DW_AT_inline (0x0200|DW_FORM_STRING) 91 | #define DW_AT_is_optional (0x0210|DW_FORM_STRING) 92 | #define DW_AT_lower_bound_ref (0x0220|DW_FORM_REF) 93 | #define DW_AT_lower_bound_data2 (0x0220|DW_FORM_DATA2) 94 | #define DW_AT_lower_bound_data4 (0x0220|DW_FORM_DATA4) 95 | #define DW_AT_lower_bound_data8 (0x0220|DW_FORM_DATA8) 96 | #define DW_AT_program (0x0230|DW_FORM_STRING) 97 | #define DW_AT_private (0x0240|DW_FORM_STRING) 98 | #define DW_AT_producer (0x0250|DW_FORM_STRING) 99 | #define DW_AT_protected (0x0260|DW_FORM_STRING) 100 | #define DW_AT_prototyped (0x0270|DW_FORM_STRING) 101 | #define DW_AT_public (0x0280|DW_FORM_STRING) 102 | #define DW_AT_pure_virtual (0x0290|DW_FORM_STRING) 103 | #define DW_AT_return_addr (0x02a0|DW_FORM_BLOCK2) 104 | #define DW_AT_specification (0x02b0|DW_FORM_REF) 105 | #define DW_AT_start_scope (0x02c0|DW_FORM_DATA4) 106 | #define DW_AT_stride_size (0x02e0|DW_FORM_DATA4) 107 | #define DW_AT_upper_bound_ref (0x02f0|DW_FORM_REF) 108 | #define DW_AT_upper_bound_data2 (0x02f0|DW_FORM_DATA2) 109 | #define DW_AT_upper_bound_data4 (0x02f0|DW_FORM_DATA4) 110 | #define DW_AT_upper_bound_data8 (0x02f0|DW_FORM_DATA8) 111 | #define DW_AT_virtual (0x0300|DW_FORM_STRING) 112 | #define DW_AT_lo_user (0x2000) 113 | #define DW_AT_hi_user (0x3ff0) 114 | // User attributes 115 | #define DW_AT_mangled_name (DW_AT_lo_user|DW_FORM_STRING) 116 | 117 | #define DW_OP_REG 0x01 118 | #define DW_OP_BASEREG 0x02 119 | #define DW_OP_ADDR 0x03 120 | #define DW_OP_CONST 0x04 121 | #define DW_OP_DEREF2 0x05 122 | #define DW_OP_DEREF 0x06 123 | #define DW_OP_DEREF4 0x06 124 | #define DW_OP_ADD 0x07 125 | #define DW_OP_lo_user 0xe0 126 | #define DW_OP_hi_user 0xff 127 | 128 | #define DW_FT_char 0x0001 129 | #define DW_FT_signed_char 0x0002 130 | #define DW_FT_unsigned_char 0x0003 131 | #define DW_FT_short 0x0004 132 | #define DW_FT_signed_short 0x0005 133 | #define DW_FT_unsigned_short 0x0006 134 | #define DW_FT_integer 0x0007 135 | #define DW_FT_signed_integer 0x0008 136 | #define DW_FT_unsigned_integer 0x0009 137 | #define DW_FT_long 0x000a 138 | #define DW_FT_signed_long 0x000b 139 | #define DW_FT_unsigned_long 0x000c 140 | #define DW_FT_pointer 0x000d 141 | #define DW_FT_float 0x000e 142 | #define DW_FT_dbl_prec_float 0x000f 143 | #define DW_FT_ext_prec_float 0x0010 144 | #define DW_FT_complex 0x0011 145 | #define DW_FT_dbl_prec_complex 0x0012 146 | #define DW_FT_void 0x0014 147 | #define DW_FT_boolean 0x0015 148 | #define DW_FT_ext_prec_complex 0x0016 149 | #define DW_FT_label 0x0017 150 | #define DW_FT_lo_user 0x8000 151 | #define DW_FT_hi_user 0xffff 152 | 153 | #define DW_FT_long_long 0x8008 154 | #define DW_FT_signed_long_long 0x8108 155 | #define DW_FT_unsigned_long_long 0x8208 156 | 157 | #define DW_MOD_pointer_to 0x01 158 | #define DW_MOD_reference_to 0x02 159 | #define DW_MOD_const 0x03 160 | #define DW_MOD_volatile 0x04 161 | #define DW_MOD_lo_user 0x80 162 | #define DW_MOD_hi_user 0xff 163 | 164 | #define DW_LANG_C89 0x00000001 165 | #define DW_LANG_C 0x00000002 166 | #define DW_LANG_ADA83 0x00000003 167 | #define DW_LANG_C_PLUS_PLUS 0x00000004 168 | #define DW_LANG_COBOL74 0x00000005 169 | #define DW_LANG_COBOL85 0x00000006 170 | #define DW_LANG_FORTRAN77 0x00000007 171 | #define DW_LANG_FORTRAN90 0x00000008 172 | #define DW_LANG_PASCAL83 0x00000009 173 | #define DW_LANG_MODULA2 0x0000000a 174 | #define DW_LANG_lo_user 0x00008000 175 | #define DW_LANG_hi_user 0x0000ffff 176 | 177 | #define DW_ORD_row_major 0 178 | #define DW_ORD_col_major 1 179 | 180 | #define DW_FMT_FT_C_C 0x0 181 | #define DW_FMT_FT_C_X 0x1 182 | #define DW_FMT_FT_X_C 0x2 183 | #define DW_FMT_FT_X_X 0x3 184 | #define DW_FMT_UT_C_C 0x4 185 | #define DW_FMT_UT_C_X 0x5 186 | #define DW_FMT_UT_X_C 0x6 187 | #define DW_FMT_UT_X_X 0x7 188 | #define DW_FMT_ET 0x8 189 | 190 | #define SHT_DWARF1 0x70000005 191 | 192 | class Dwarf 193 | { 194 | public: 195 | enum Error 196 | { 197 | ERR_NONE = 0, 198 | ERR_NO_DWARF, 199 | ERR_INVALID_ENTRY, 200 | ERR_INVALID_ATTRIBUTE 201 | }; 202 | 203 | struct Attribute; 204 | struct Entry; 205 | 206 | struct Attribute 207 | { 208 | Dwarf* dwarf; 209 | int entryIndex; 210 | Elf32_Off offset; 211 | Elf32_Half name; 212 | Elf32_Word size; 213 | void *value; 214 | 215 | inline Elf32_Half getForm() 216 | { 217 | return name & 0xf; 218 | } 219 | 220 | inline Elf32_Addr getAddress() 221 | { 222 | return dwarf->read(value); 223 | } 224 | 225 | inline Elf32_Off getReference() 226 | { 227 | return dwarf->read(value); 228 | } 229 | 230 | inline char* getBlock() 231 | { 232 | return (char*)value; 233 | } 234 | 235 | inline Elf32_Half getHword() 236 | { 237 | return dwarf->read(value); 238 | } 239 | 240 | inline Elf32_Word getWord() 241 | { 242 | return dwarf->read(value); 243 | } 244 | 245 | inline uint64_t getDword() 246 | { 247 | return dwarf->read(value); 248 | } 249 | 250 | inline char* getString() 251 | { 252 | return (char*)value; 253 | } 254 | }; 255 | 256 | struct Entry 257 | { 258 | Dwarf *dwarf; 259 | Elf32_Off offset; 260 | int index; 261 | Elf32_Word length; 262 | Elf32_Half tag; 263 | std::vector attributes; 264 | 265 | inline bool isNullEntry() 266 | { 267 | return length < 8; 268 | } 269 | 270 | inline Entry* getSibling() 271 | { 272 | if (index == dwarf->entries.size() - 1) 273 | return nullptr; 274 | 275 | size_t numAttributes = attributes.size(); 276 | 277 | for (size_t i = 0; i < numAttributes; i++) 278 | { 279 | Attribute *attr = &attributes[i]; 280 | 281 | if (attr->name == DW_AT_sibling) 282 | { 283 | Elf32_Off offset = attr->getReference(); 284 | Entry *sibling = dwarf->getEntryFromReference(offset); 285 | 286 | if (sibling) 287 | return sibling; 288 | 289 | break; 290 | } 291 | } 292 | 293 | return this + 1; 294 | } 295 | }; 296 | 297 | struct LineEntry 298 | { 299 | int lineNumber; 300 | short charOffset; 301 | int hexAddressOffset; 302 | }; 303 | 304 | std::multimap lineEntryMap; 305 | std::vector entries; 306 | 307 | Dwarf(ElfFile *elf) 308 | { 309 | m_error = ERR_NONE; 310 | m_elf = elf; 311 | 312 | m_section = m_elf->getSectionHeader(".debug"); 313 | 314 | if (!m_section) 315 | { 316 | m_error = ERR_NO_DWARF; 317 | return; 318 | } 319 | 320 | m_sectionData = m_elf->getSectionData(m_section); 321 | m_sectionSize = m_section->sh_size; 322 | 323 | Elf32_Off offset = 0; 324 | 325 | while (offset < m_sectionSize && !m_error) 326 | offset = readEntry(offset); 327 | 328 | // Read debug line data. 329 | Elf32_Shdr* m_lineHeader; 330 | m_lineHeader = m_elf->getSectionHeader(".line"); 331 | if (m_lineHeader) 332 | { 333 | char* m_lineSectionDataStart; 334 | char* m_lineSectionData; 335 | m_lineSectionDataStart = m_elf->getSectionData(m_lineHeader); 336 | m_lineSectionData = m_lineSectionDataStart; 337 | 338 | while (m_lineHeader->sh_size > (int)(m_lineSectionData - m_lineSectionDataStart)) { 339 | int byteSize; 340 | int funcPtr; 341 | char* m_lineSectionDataChunkEnd; 342 | m_lineSectionDataChunkEnd = m_lineSectionData; 343 | 344 | byteSize = read(m_lineSectionData); 345 | m_lineSectionData += sizeof(int); 346 | m_lineSectionDataChunkEnd += byteSize; 347 | 348 | funcPtr = read(m_lineSectionData); 349 | m_lineSectionData += sizeof(int); 350 | 351 | while (m_lineSectionDataChunkEnd > m_lineSectionData) { 352 | LineEntry entry; 353 | 354 | entry.lineNumber = read(m_lineSectionData); 355 | m_lineSectionData += sizeof(int); 356 | entry.charOffset = read(m_lineSectionData); 357 | m_lineSectionData += sizeof(short); 358 | entry.hexAddressOffset = read(m_lineSectionData); 359 | m_lineSectionData += sizeof(int); 360 | lineEntryMap.insert(std::pair(funcPtr, entry)); 361 | if (entry.lineNumber == 0) 362 | break; // End. 363 | } 364 | } 365 | } 366 | } 367 | 368 | Elf32_Off readEntry(Elf32_Off offset, int *outIndex = nullptr) 369 | { 370 | Entry entry; 371 | 372 | entry.dwarf = this; 373 | entry.index = entries.size(); 374 | entry.offset = offset; 375 | entry.length = read(m_sectionData + offset); 376 | 377 | m_entryIndexRefMap[offset] = entry.index; 378 | 379 | Elf32_Word end = offset + entry.length; 380 | 381 | if (entry.isNullEntry()) // Null entry 382 | offset = end; 383 | else 384 | { 385 | offset += sizeof(Elf32_Word); 386 | 387 | entry.tag = read(m_sectionData + offset); 388 | offset += sizeof(Elf32_Half); 389 | 390 | while (offset < end && !m_error) 391 | offset = readAttribute(offset, &entry); 392 | 393 | if (offset > end) 394 | { 395 | m_error = ERR_INVALID_ENTRY; 396 | return 0; 397 | } 398 | } 399 | 400 | entries.push_back(entry); 401 | 402 | if (outIndex) 403 | *outIndex = entry.index; 404 | 405 | return offset; 406 | } 407 | 408 | Elf32_Off readAttribute(Elf32_Off offset, Entry *entry, int *outIndex = nullptr) 409 | { 410 | Attribute attribute; 411 | 412 | attribute.dwarf = entry->dwarf; 413 | attribute.entryIndex = entry->index; 414 | attribute.offset = offset; 415 | attribute.name = read(m_sectionData + offset); 416 | offset += sizeof(Elf32_Half); 417 | 418 | Elf32_Half form = attribute.getForm(); 419 | 420 | switch (form) 421 | { 422 | case DW_FORM_ADDR: 423 | attribute.size = sizeof(Elf32_Addr); 424 | break; 425 | case DW_FORM_REF: 426 | attribute.size = sizeof(Elf32_Off); 427 | break; 428 | case DW_FORM_BLOCK2: 429 | attribute.size = read(m_sectionData + offset); 430 | offset += sizeof(Elf32_Half); 431 | break; 432 | case DW_FORM_BLOCK4: 433 | attribute.size = read(m_sectionData + offset); 434 | offset += sizeof(Elf32_Word); 435 | break; 436 | case DW_FORM_DATA2: 437 | attribute.size = sizeof(Elf32_Half); 438 | break; 439 | case DW_FORM_DATA4: 440 | attribute.size = sizeof(Elf32_Word); 441 | break; 442 | case DW_FORM_DATA8: 443 | attribute.size = sizeof(uint64_t); 444 | break; 445 | case DW_FORM_STRING: 446 | attribute.size = strlen(m_sectionData + offset) + 1; 447 | break; 448 | default: 449 | m_error = ERR_INVALID_ATTRIBUTE; 450 | return 0; 451 | } 452 | 453 | attribute.value = m_sectionData + offset; 454 | 455 | int index = entry->attributes.size(); 456 | 457 | entry->attributes.push_back(attribute); 458 | 459 | if (outIndex) 460 | *outIndex = index; 461 | 462 | return offset + attribute.size; 463 | } 464 | 465 | inline Error getError() 466 | { 467 | return m_error; 468 | } 469 | 470 | inline Entry* getEntryFromReference(Elf32_Off ref) 471 | { 472 | if (m_entryIndexRefMap.count(ref) == 0) 473 | return nullptr; 474 | 475 | return &entries[m_entryIndexRefMap[ref]]; 476 | } 477 | 478 | inline Elf32_Off pointerToOffset(char *ptr) 479 | { 480 | return ptr - m_sectionData; 481 | } 482 | 483 | inline char* offsetToPointer(Elf32_Off offset) 484 | { 485 | return m_sectionData + offset; 486 | } 487 | 488 | template 489 | inline T read(void *data) 490 | { 491 | return m_elf->read(data); 492 | } 493 | 494 | private: 495 | Error m_error; 496 | 497 | ElfFile *m_elf; 498 | Elf32_Shdr *m_section; 499 | char *m_sectionData; 500 | Elf32_Word m_sectionSize; 501 | 502 | std::unordered_map m_entryIndexRefMap; 503 | }; 504 | -------------------------------------------------------------------------------- /dwarf2cpp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.645 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dwarf2cpp", "dwarf2cpp.vcxproj", "{A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}.Debug|x64.ActiveCfg = Debug|x64 17 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}.Debug|x64.Build.0 = Debug|x64 18 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}.Debug|x86.ActiveCfg = Debug|Win32 19 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}.Debug|x86.Build.0 = Debug|Win32 20 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}.Release|x64.ActiveCfg = Release|x64 21 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}.Release|x64.Build.0 = Release|x64 22 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}.Release|x86.ActiveCfg = Release|Win32 23 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {F5383D0E-511B-4011-8269-79FF977AD154} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /dwarf2cpp.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {A9C933B4-DB33-4B04-95C2-668CDBA8CB4A} 24 | dwarf2cpp 25 | 10.0.17763.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | $(ProjectDir);$(IncludePath) 74 | 75 | 76 | $(ProjectDir);$(IncludePath) 77 | 78 | 79 | 80 | Level3 81 | Disabled 82 | true 83 | true 84 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | true 92 | true 93 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 94 | 95 | 96 | 97 | 98 | Level3 99 | MaxSpeed 100 | true 101 | true 102 | true 103 | true 104 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 105 | 106 | 107 | true 108 | true 109 | 110 | 111 | 112 | 113 | Level3 114 | MaxSpeed 115 | true 116 | true 117 | true 118 | true 119 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 120 | 121 | 122 | true 123 | true 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /dwarf2cpp.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 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /elf.h: -------------------------------------------------------------------------------- 1 | /**********************************************************/ 2 | /* http://www.skyfree.org/linux/references/ELF_Format.pdf */ 3 | /**********************************************************/ 4 | 5 | // Only supports 32-bit files currently :( 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | typedef uint32_t Elf32_Addr; 14 | typedef uint16_t Elf32_Half; 15 | typedef uint32_t Elf32_Off; 16 | typedef int32_t Elf32_Sword; 17 | typedef uint32_t Elf32_Word; 18 | 19 | #define EI_MAG0 0 20 | #define EI_MAG1 1 21 | #define EI_MAG2 2 22 | #define EI_MAG3 3 23 | #define EI_CLASS 4 24 | #define EI_DATA 5 25 | #define EI_VERSION 6 26 | #define EI_PAD 7 27 | #define EI_NIDENT 16 28 | 29 | #define ELFCLASSNONE 0 30 | #define ELFCLASS32 1 31 | #define ELFCLASS64 2 32 | 33 | #define ELFDATANONE 0 34 | #define ELFDATA2LSB 1 35 | #define ELFDATA2MSB 2 36 | 37 | #define ET_NONE 0 38 | #define ET_REL 1 39 | #define ET_EXEC 2 40 | #define ET_DYN 3 41 | #define ET_CORE 4 42 | #define ET_LOPROC 0xff00 43 | #define ET_HIPROC 0xffff 44 | 45 | #define EM_NONE 0 46 | #define EM_M32 1 47 | #define EM_SPARC 2 48 | #define EM_386 3 49 | #define EM_68K 4 50 | #define EM_88K 5 51 | #define EM_860 7 52 | #define EM_MIPS 8 53 | 54 | #define EV_NONE 0 55 | #define EV_CURRENT 1 56 | 57 | #define SHN_UNDEF 0 58 | #define SHN_LORESERVE 0xff00 59 | #define SHN_LOPROC 0xff00 60 | #define SHN_HIPROC 0xff1f 61 | #define SHN_ABS 0xfff1 62 | #define SHN_COMMON 0xfff2 63 | #define SHN_HIRESERVE 0xffff 64 | 65 | #define swap4(x) (((x >> 24) & 0xff) | ((x << 8) & 0xff0000) |\ 66 | ((x >> 8) & 0xff00) | ((x << 24) & 0xff000000)) 67 | #define swap2(x) (((x << 8) & 0xff00) | ((x >> 8) & 0x00ff)) 68 | 69 | struct Elf32_Ehdr 70 | { 71 | unsigned char e_ident[EI_NIDENT]; 72 | Elf32_Half e_type; 73 | Elf32_Half e_machine; 74 | Elf32_Word e_version; 75 | Elf32_Addr e_entry; 76 | Elf32_Off e_phoff; 77 | Elf32_Off e_shoff; 78 | Elf32_Word e_flags; 79 | Elf32_Half e_ehsize; 80 | Elf32_Half e_phentsize; 81 | Elf32_Half e_phnum; 82 | Elf32_Half e_shentsize; 83 | Elf32_Half e_shnum; 84 | Elf32_Half e_shstrndx; 85 | }; 86 | 87 | struct Elf32_Shdr 88 | { 89 | Elf32_Word sh_name; 90 | Elf32_Word sh_type; 91 | Elf32_Word sh_flags; 92 | Elf32_Addr sh_addr; 93 | Elf32_Off sh_offset; 94 | Elf32_Word sh_size; 95 | Elf32_Word sh_link; 96 | Elf32_Word sh_info; 97 | Elf32_Word sh_addralign; 98 | Elf32_Word sh_entsize; 99 | }; 100 | 101 | class ElfFile 102 | { 103 | public: 104 | enum Error 105 | { 106 | ERR_NONE = 0, 107 | ERR_FILE_NOT_OPEN, 108 | ERR_FILE_EMPTY, 109 | ERR_FILE_READ, 110 | ERR_INVALID_HEADER 111 | }; 112 | 113 | ElfFile(const char *filename) 114 | { 115 | m_error = ERR_NONE; 116 | 117 | loadFile(filename); 118 | initEndian(); 119 | 120 | if (m_error) 121 | return; 122 | 123 | Elf32_Ehdr *ehdr = getElfHeader(); 124 | 125 | if (ehdr->e_ident[EI_MAG0] != 0x7f || 126 | ehdr->e_ident[EI_MAG1] != 'E' || 127 | ehdr->e_ident[EI_MAG2] != 'L' || 128 | ehdr->e_ident[EI_MAG3] != 'F' || 129 | ehdr->e_ident[EI_CLASS] != ELFCLASS32 || 130 | ehdr->e_ident[EI_DATA] == ELFDATANONE || 131 | ehdr->e_ident[EI_VERSION] == EV_NONE || 132 | read(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) || 133 | read(&ehdr->e_shentsize) != sizeof(Elf32_Shdr) || 134 | read(&ehdr->e_version) == EV_NONE) 135 | { 136 | m_error = ERR_INVALID_HEADER; 137 | } 138 | } 139 | 140 | inline Elf32_Ehdr* getElfHeader() const 141 | { 142 | return (Elf32_Ehdr*)m_file; 143 | } 144 | 145 | inline unsigned char getClass() const 146 | { 147 | return getElfHeader()->e_ident[EI_CLASS]; 148 | } 149 | 150 | inline unsigned char getDataEncoding() const 151 | { 152 | return getElfHeader()->e_ident[EI_DATA]; 153 | } 154 | 155 | inline Elf32_Shdr* getSectionHeader(Elf32_Half index) const 156 | { 157 | return (Elf32_Shdr*)(m_file + getElfHeader()->e_shoff) + index; 158 | } 159 | 160 | inline char* getSectionName(Elf32_Shdr *shdr) const 161 | { 162 | return m_file + getSectionHeader(getElfHeader()->e_shstrndx)->sh_offset + shdr->sh_name; 163 | } 164 | 165 | inline char* getSectionData(Elf32_Shdr *shdr) const 166 | { 167 | return m_file + shdr->sh_offset; 168 | } 169 | 170 | inline Elf32_Shdr* getSectionHeader(const char *name) const 171 | { 172 | for (int i = 0; i < getElfHeader()->e_shnum; i++) 173 | { 174 | if (strcmp(getSectionName(getSectionHeader(i)), name) == 0) 175 | return getSectionHeader(i); 176 | } 177 | 178 | return nullptr; 179 | } 180 | 181 | inline Error getError() const 182 | { 183 | return m_error; 184 | } 185 | 186 | template 187 | inline T read(void *data) 188 | { 189 | T x = *(T*)data; 190 | 191 | if (m_shouldReverseEndian) 192 | { 193 | if (sizeof(T) == 2) 194 | x = swap2((uint16_t)x); 195 | else 196 | x = swap4((uint32_t)x); 197 | } 198 | 199 | return x; 200 | } 201 | 202 | private: 203 | Error m_error; 204 | char *m_file; 205 | bool m_shouldReverseEndian; 206 | 207 | void loadFile(const char *filename) 208 | { 209 | FILE *file = fopen(filename, "rb"); 210 | 211 | if (!file) 212 | { 213 | m_error = ERR_FILE_NOT_OPEN; 214 | return; 215 | } 216 | 217 | fseek(file, 0, SEEK_END); 218 | int size = ftell(file); 219 | fseek(file, 0, SEEK_SET); 220 | 221 | if (size == 0) 222 | { 223 | m_error = ERR_FILE_EMPTY; 224 | fclose(file); 225 | return; 226 | } 227 | 228 | m_file = new char[size]; 229 | 230 | size_t bytesRead = fread(m_file, sizeof(char), size, file); 231 | fclose(file); 232 | 233 | if (bytesRead != size) 234 | { 235 | m_error = ERR_FILE_READ; 236 | } 237 | } 238 | 239 | inline void initEndian() 240 | { 241 | int x = 1; 242 | m_shouldReverseEndian = (*(char*)&x == 1 && getDataEncoding() != ELFDATA2LSB); 243 | } 244 | }; -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "elf.h" 2 | #include "dwarf.h" 3 | #include "cpp.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING 11 | #include 12 | 13 | namespace filesystem = std::experimental::filesystem; 14 | 15 | std::vector cppFiles; 16 | std::map entryUTPairs; 17 | std::map> nameUTListPairs; 18 | 19 | int currentCompileUnitIndex = 0; 20 | 21 | Cpp::File* findCppFile(Dwarf::Entry *entry, const char **outFilename); 22 | void fixUserTypeNames(); 23 | 24 | bool processDwarf(Dwarf *dwarf); 25 | bool processCompileUnit(Dwarf::Entry *entry, Cpp::File *cpp); 26 | bool processVariable(Dwarf::Entry *entry, Cpp::Variable *var); 27 | bool processTypeAttr(Dwarf::Attribute *attr, Cpp::Type *type); 28 | bool processLocationAttr(Dwarf::Attribute *attr, int *location); 29 | bool findUserType(Dwarf *dwarf, Elf32_Off ref, Cpp::UserType **u); 30 | bool processUserType(Dwarf::Entry *entry, Cpp::UserType *u); 31 | bool processClassType(Dwarf::Entry *entry, Cpp::ClassType *c); 32 | bool processMember(Dwarf::Entry *entry, Cpp::ClassType::Member *m); 33 | bool processInheritance(Dwarf::Entry *entry, Cpp::ClassType::Inheritance *i_); 34 | bool processEnumType(Dwarf::Entry *entry, Cpp::EnumType *e); 35 | bool processElementList(Dwarf::Attribute *attr, Cpp::EnumType *e, int byte_size); 36 | bool processFunctionType(Dwarf::Entry *entry, Cpp::FunctionType *f); 37 | bool processParameter(Dwarf::Entry *entry, Cpp::FunctionType::Parameter *p); 38 | bool processFunction(Dwarf::Entry *entry, Cpp::Function *f); 39 | bool processLexicalBlock(Dwarf::Entry *entry, Cpp::Function *f); 40 | bool processArrayType(Dwarf::Entry *entry, Cpp::ArrayType *a); 41 | bool processSubscriptData(Dwarf::Attribute *attr, Cpp::ArrayType *a); 42 | void replaceChar(char *str, char ch, char newCh); 43 | 44 | static inline std::string toHexString(int x) 45 | { 46 | std::stringstream ss; 47 | ss << std::hex << std::showbase << x; 48 | return ss.str(); 49 | } 50 | 51 | bool error(std::string errorMessage) { 52 | std::cout << "ERROR: " << errorMessage << std::endl; 53 | return false; 54 | } 55 | 56 | int main(int argc, char **argv) 57 | { 58 | if (argc != 3) 59 | { 60 | std::cout << "Usage: dwarf2cpp "; 61 | return 1; 62 | } 63 | 64 | char *elfFilename = argv[1]; 65 | char *outDirectory = argv[2]; 66 | 67 | std::cout << "Loading ELF file " << elfFilename << "..." << std::endl; 68 | 69 | ElfFile *elf = new ElfFile(elfFilename); 70 | 71 | if (elf->getError()) { 72 | std::cout << "Failed to parse " << elfFilename << " as an ELF file. Error Code: " << elf->getError() << std::endl; 73 | return 1; 74 | } 75 | 76 | std::cout << "Loading DWARFv1 information..." << std::endl; 77 | 78 | Dwarf *dwarf = new Dwarf(elf); 79 | 80 | if (dwarf->getError()) { 81 | std::cout << "Failed to parse DWARF data. Error Code: " << dwarf->getError() << std::endl; 82 | return 1; 83 | } 84 | 85 | std::cout << "Converting DWARFv1 entries to C++ data..." << std::endl; 86 | 87 | if (!processDwarf(dwarf)) { 88 | std::cout << "Failed to process DWARF data." << std::endl; 89 | return 1; 90 | } 91 | 92 | std::cout << "Done converting DWARFv1 data!" << std::endl; 93 | std::cout << "\tNumber of C++ files: " << cppFiles.size() << std::endl << std::endl; 94 | 95 | for (Cpp::File *cpp : cppFiles) 96 | { 97 | size_t pos; 98 | while ((pos = cpp->filename.find("\\")) != std::string::npos) 99 | { 100 | cpp->filename.replace(pos, 1, "/"); 101 | } 102 | 103 | filesystem::path filename(cpp->filename); 104 | filesystem::path path(outDirectory); 105 | 106 | path /= filename.relative_path(); 107 | path = path.make_preferred(); 108 | 109 | filesystem::create_directories(path.parent_path()); 110 | 111 | std::cout << "Writing file " << path << "..." << std::endl; 112 | 113 | std::ofstream file(path); 114 | file << cpp->toString(false, false); 115 | file.close(); 116 | } 117 | 118 | std::cout << "Done." << std::endl; 119 | 120 | return 0; 121 | } 122 | 123 | Cpp::File* findCppFile(Dwarf::Entry *entry, const char **outFilename) 124 | { 125 | *outFilename = nullptr; 126 | 127 | size_t numAttributes = entry->attributes.size(); 128 | 129 | for (size_t i = 0; i < numAttributes; i++) 130 | { 131 | Dwarf::Attribute *attr = &entry->attributes[i]; 132 | 133 | if (attr->name == DW_AT_name) 134 | { 135 | *outFilename = attr->getString(); 136 | break; 137 | } 138 | } 139 | 140 | if (*outFilename) 141 | { 142 | for (Cpp::File *cpp : cppFiles) 143 | { 144 | if (cpp->filename == *outFilename) 145 | return cpp; 146 | } 147 | } 148 | 149 | return nullptr; 150 | } 151 | 152 | void fixUserTypeNames() 153 | { 154 | for (auto const &x : nameUTListPairs) 155 | { 156 | bool noname = x.first.empty(); 157 | bool duplicate = x.second.size() > 1; 158 | 159 | if (noname || duplicate) 160 | { 161 | for (size_t i = 0; i < x.second.size(); i++) 162 | { 163 | Cpp::UserType *ut = x.second[i]; 164 | 165 | if (noname) 166 | ut->name = "type"; 167 | 168 | if (duplicate) 169 | ut->name += "_" + std::to_string(i); 170 | } 171 | } 172 | } 173 | } 174 | 175 | bool processDwarf(Dwarf *dwarf) 176 | { 177 | Dwarf::Entry *entry = &dwarf->entries.front(); 178 | 179 | while (entry) 180 | { 181 | switch (entry->tag) 182 | { 183 | case DW_TAG_compile_unit: 184 | { 185 | const char *filename; 186 | Cpp::File *cpp = findCppFile(entry, &filename); 187 | 188 | bool found = (cpp != nullptr); 189 | 190 | if (!found) 191 | { 192 | cpp = new Cpp::File; 193 | cpp->filename = filename; 194 | } 195 | 196 | if (!processCompileUnit(entry, cpp)) 197 | return error(std::string("Failed to processCompileUnit for '").append(cpp->filename).append("'")); 198 | 199 | if (!found) 200 | cppFiles.push_back(cpp); 201 | 202 | //std::cout << "Found compile unit " << cpp->filename << std::endl; 203 | //std::cout << "\t" << std::to_string(cpp->userTypes.size()) << " user types" << std::endl; 204 | //std::cout << "\t" << std::to_string(cpp->variables.size()) << " variables" << std::endl; 205 | 206 | break; 207 | } 208 | } 209 | 210 | entry = entry->getSibling(); 211 | } 212 | 213 | return true; 214 | } 215 | 216 | bool processCompileUnit(Dwarf::Entry *entry, Cpp::File *cpp) 217 | { 218 | nameUTListPairs.clear(); 219 | 220 | Dwarf::Entry *next = entry->getSibling(); 221 | size_t numAttributes = entry->attributes.size(); 222 | 223 | for (size_t i = 0; i < numAttributes; i++) 224 | { 225 | Dwarf::Attribute *attr = &entry->attributes[i]; 226 | 227 | switch (attr->name) 228 | { 229 | case DW_AT_name: 230 | cpp->filename = attr->getString(); 231 | break; 232 | } 233 | } 234 | 235 | Dwarf::Entry *start = ++entry; 236 | 237 | while (entry && entry < next) 238 | { 239 | switch (entry->tag) 240 | { 241 | case DW_TAG_class_type: 242 | case DW_TAG_structure_type: 243 | case DW_TAG_enumeration_type: 244 | case DW_TAG_array_type: 245 | case DW_TAG_subroutine_type: 246 | case DW_TAG_union_type: 247 | { 248 | entryUTPairs[entry] = new Cpp::UserType; 249 | } 250 | } 251 | 252 | entry = entry->getSibling(); 253 | } 254 | 255 | entry = start; 256 | 257 | while (entry && entry < next) 258 | { 259 | switch (entry->tag) 260 | { 261 | case DW_TAG_global_variable: 262 | case DW_TAG_local_variable: 263 | { 264 | Cpp::Variable var; 265 | 266 | if (!processVariable(entry, &var)) 267 | return error("Failed to processVar."); 268 | 269 | cpp->variables.push_back(var); 270 | break; 271 | } 272 | case DW_TAG_class_type: 273 | case DW_TAG_structure_type: 274 | case DW_TAG_enumeration_type: 275 | case DW_TAG_array_type: 276 | case DW_TAG_subroutine_type: 277 | case DW_TAG_union_type: 278 | { 279 | Cpp::UserType *userType = entryUTPairs[entry]; 280 | processUserType(entry, userType); 281 | 282 | userType->index = cpp->userTypes.size(); 283 | cpp->userTypes.push_back(userType); 284 | 285 | nameUTListPairs[userType->name].push_back(userType); 286 | break; 287 | } 288 | case DW_TAG_global_subroutine: 289 | case DW_TAG_subroutine: 290 | case DW_TAG_inlined_subroutine: 291 | { 292 | Cpp::Function f; 293 | f.dwarf = entry->dwarf; 294 | 295 | if (!processFunctionType(entry, &f)) 296 | return error("Failed to processFunctionType."); 297 | 298 | if (!processFunction(entry, &f)) 299 | return error("Failed to processFunction."); 300 | 301 | cpp->functions.push_back(f); 302 | } 303 | } 304 | 305 | entry = entry->getSibling(); 306 | } 307 | 308 | fixUserTypeNames(); 309 | 310 | return true; 311 | } 312 | 313 | bool processVariable(Dwarf::Entry *entry, Cpp::Variable *var) 314 | { 315 | var->isGlobal = (entry->tag == DW_TAG_global_variable); 316 | 317 | size_t numAttributes = entry->attributes.size(); 318 | 319 | for (size_t i = 0; i < numAttributes; i++) 320 | { 321 | Dwarf::Attribute *attr = &entry->attributes[i]; 322 | 323 | switch (attr->name) 324 | { 325 | case DW_AT_name: 326 | var->name = attr->getString(); 327 | break; 328 | case DW_AT_fund_type: 329 | case DW_AT_user_def_type: 330 | case DW_AT_mod_fund_type: 331 | case DW_AT_mod_u_d_type: 332 | if (!processTypeAttr(attr, &var->type)) 333 | return error(std::string("Failed to processTypeAttr for variable '").append(var->name).append("'.")); 334 | break; 335 | } 336 | } 337 | 338 | return true; 339 | } 340 | 341 | bool processTypeAttr(Dwarf::Attribute *attr, Cpp::Type *type) 342 | { 343 | Dwarf *dwarf = attr->dwarf; 344 | 345 | switch (attr->name) 346 | { 347 | case DW_AT_fund_type: 348 | { 349 | type->isFundamentalType = true; 350 | type->fundamentalType = (Cpp::FundamentalType)attr->getHword(); 351 | break; 352 | } 353 | case DW_AT_user_def_type: 354 | { 355 | type->isFundamentalType = false; 356 | 357 | if (!findUserType(dwarf, attr->getReference(), &type->userType)) 358 | return error(std::string("processTypeAttr failed when handling AT_user_def_type.")); 359 | 360 | break; 361 | } 362 | case DW_AT_mod_fund_type: 363 | { 364 | type->isFundamentalType = true; 365 | 366 | char *mod = attr->getBlock(); 367 | char *end = mod + attr->size - sizeof(Elf32_Half); 368 | 369 | type->fundamentalType = (Cpp::FundamentalType)dwarf->read(end); 370 | 371 | while (mod < end) 372 | { 373 | type->modifiers.push_back((Cpp::Type::Modifier)*mod); 374 | mod++; 375 | } 376 | 377 | break; 378 | } 379 | case DW_AT_mod_u_d_type: 380 | { 381 | type->isFundamentalType = false; 382 | 383 | char *mod = attr->getBlock(); 384 | char *end = mod + attr->size - sizeof(Elf32_Off); 385 | 386 | if (!findUserType(dwarf, dwarf->read(end), &type->userType)) 387 | return error(std::string("processTypeAttr failed when handling AT_mod_u_d_type.")); 388 | 389 | while (mod < end) 390 | { 391 | type->modifiers.push_back((Cpp::Type::Modifier)*mod); 392 | mod++; 393 | } 394 | 395 | break; 396 | } 397 | } 398 | 399 | return true; 400 | } 401 | 402 | bool processLocationAttr(Dwarf::Attribute *attr, int *location) 403 | { 404 | // I don't really know how location is supposed to be handled, 405 | // so I just look for a DW_OP_CONST and use that as the "location" 406 | 407 | Dwarf *dwarf = attr->dwarf; 408 | 409 | char *block = attr->getBlock(); 410 | char *end = block + attr->size; 411 | 412 | while (block < end) 413 | { 414 | char op = dwarf->read(block); 415 | block += sizeof(char); 416 | 417 | if (op == DW_OP_CONST) 418 | { 419 | *location = dwarf->read(block); 420 | break; 421 | } 422 | } 423 | 424 | return true; 425 | } 426 | 427 | bool findUserType(Dwarf *dwarf, Elf32_Off ref, Cpp::UserType **u) 428 | { 429 | Dwarf::Entry *entry = dwarf->getEntryFromReference(ref); 430 | 431 | if (!entry || entryUTPairs.count(entry) == 0) 432 | return error(std::string("Failed to findUserType for reference '").append(std::to_string(ref)).append("'.")); 433 | 434 | *u = entryUTPairs[entry]; 435 | 436 | return true; 437 | } 438 | 439 | bool processUserType(Dwarf::Entry *entry, Cpp::UserType *userType) 440 | { 441 | size_t numAttributes = entry->attributes.size(); 442 | 443 | for (size_t i = 0; i < numAttributes; i++) 444 | { 445 | Dwarf::Attribute *attr = &entry->attributes[i]; 446 | 447 | switch (attr->name) 448 | { 449 | case DW_AT_name: 450 | { 451 | char *name = attr->getString(); 452 | replaceChar(name, '@', '_'); 453 | userType->name = name; 454 | break; 455 | } 456 | } 457 | } 458 | 459 | switch (entry->tag) 460 | { 461 | case DW_TAG_class_type: 462 | case DW_TAG_structure_type: 463 | case DW_TAG_union_type: 464 | userType->type = (entry->tag == DW_TAG_structure_type) ? Cpp::UserType::STRUCT : ((entry->tag == DW_TAG_union_type) ? Cpp::UserType::UNION : Cpp::UserType::CLASS); 465 | userType->classData = new Cpp::ClassType; 466 | userType->classData->parent = userType; 467 | 468 | if (!processClassType(entry, userType->classData)) 469 | return error(std::string("Failed to processClassType for user type '").append(userType->name).append("'.")); 470 | 471 | break; 472 | case DW_TAG_enumeration_type: 473 | userType->type = Cpp::UserType::ENUM; 474 | userType->enumData = new Cpp::EnumType; 475 | 476 | if (!processEnumType(entry, userType->enumData)) 477 | return error(std::string("Failed to processEnumType for user type '").append(userType->name).append("'.")); 478 | 479 | break; 480 | case DW_TAG_array_type: 481 | userType->type = Cpp::UserType::ARRAY; 482 | userType->arrayData = new Cpp::ArrayType; 483 | 484 | if (!processArrayType(entry, userType->arrayData)) 485 | return error(std::string("Failed to processArrayType for array type '").append(userType->name).append("'.")); 486 | 487 | break; 488 | case DW_TAG_subroutine_type: 489 | userType->type = Cpp::UserType::FUNCTION; 490 | userType->functionData = new Cpp::FunctionType; 491 | 492 | if (!processFunctionType(entry, userType->functionData)) 493 | return error(std::string("Failed to processFunctionType for function type '").append(userType->name).append("'.")); 494 | 495 | break; 496 | } 497 | 498 | return true; 499 | } 500 | 501 | bool processClassType(Dwarf::Entry *entry, Cpp::ClassType *c) 502 | { 503 | c->size = 0; 504 | 505 | size_t numAttributes = entry->attributes.size(); 506 | 507 | for (size_t i = 0; i < numAttributes; i++) 508 | { 509 | Dwarf::Attribute *attr = &entry->attributes[i]; 510 | 511 | switch (attr->name) 512 | { 513 | case DW_AT_byte_size: 514 | c->size = attr->getWord(); 515 | break; 516 | } 517 | } 518 | 519 | Dwarf::Entry *next = entry->getSibling(); 520 | Dwarf::Entry *first = entry; 521 | 522 | int memberCount = 0; 523 | entry++; 524 | 525 | while (entry && entry < next) 526 | { 527 | if (entry->tag == DW_TAG_member) 528 | memberCount++; 529 | 530 | entry = entry->getSibling(); 531 | } 532 | 533 | c->members.reserve(memberCount); 534 | entry = first + 1; 535 | 536 | while (entry && entry < next) 537 | { 538 | switch (entry->tag) 539 | { 540 | case DW_TAG_member: 541 | { 542 | Cpp::ClassType::Member m; 543 | 544 | if (!processMember(entry, &m)) 545 | return error("Failed to processMember for class type."); 546 | 547 | c->members.push_back(m); 548 | break; 549 | } 550 | case DW_TAG_inheritance: 551 | Cpp::ClassType::Inheritance i; 552 | 553 | if (!processInheritance(entry, &i)) 554 | return error("Failed to processInheritance for class type."); 555 | 556 | c->inheritances.push_back(i); 557 | break; 558 | } 559 | 560 | entry = entry->getSibling(); 561 | } 562 | 563 | return true; 564 | } 565 | 566 | bool processMember(Dwarf::Entry *entry, Cpp::ClassType::Member *m) 567 | { 568 | m->bit_offset = -1; 569 | m->bit_size = -1; 570 | 571 | size_t numAttributes = entry->attributes.size(); 572 | 573 | for (size_t i = 0; i < numAttributes; i++) 574 | { 575 | Dwarf::Attribute *attr = &entry->attributes[i]; 576 | 577 | switch (attr->name) 578 | { 579 | case DW_AT_name: 580 | m->name = attr->getString(); 581 | break; 582 | case DW_AT_bit_offset: 583 | m->bit_offset = attr->getHword(); 584 | break; 585 | case DW_AT_bit_size: 586 | m->bit_size = attr->getWord(); 587 | break; 588 | case DW_AT_fund_type: 589 | case DW_AT_user_def_type: 590 | case DW_AT_mod_fund_type: 591 | case DW_AT_mod_u_d_type: 592 | if (!processTypeAttr(attr, &m->type)) 593 | return error(std::string("Failed to processTypeAttr for member '").append(m->name).append("'.")); 594 | break; 595 | case DW_AT_location: 596 | if (!processLocationAttr(attr, &m->offset)) 597 | return error(std::string("Failed to processLocationAttr for member '").append(m->name).append("'.")); 598 | } 599 | } 600 | 601 | return true; 602 | } 603 | 604 | bool processInheritance(Dwarf::Entry *entry, Cpp::ClassType::Inheritance *i_) 605 | { 606 | size_t numAttributes = entry->attributes.size(); 607 | 608 | for (size_t i = 0; i < numAttributes; i++) 609 | { 610 | Dwarf::Attribute *attr = &entry->attributes[i]; 611 | 612 | switch (attr->name) 613 | { 614 | case DW_AT_user_def_type: 615 | if (!processTypeAttr(attr, &i_->type)) 616 | return error("Failed to processTypeAttr for inheritance."); 617 | break; 618 | case DW_AT_location: 619 | if (!processLocationAttr(attr, &i_->offset)) 620 | return error("Failed to processLocationAttr for inheritance."); 621 | } 622 | } 623 | 624 | return true; 625 | } 626 | 627 | bool processEnumType(Dwarf::Entry *entry, Cpp::EnumType *e) 628 | { 629 | int byte_size = 0; 630 | size_t numAttributes = entry->attributes.size(); 631 | 632 | for (size_t i = 0; i < numAttributes; i++) 633 | { 634 | Dwarf::Attribute *attr = &entry->attributes[i]; 635 | 636 | switch (attr->name) 637 | { 638 | case DW_AT_byte_size: 639 | byte_size = attr->getWord(); 640 | 641 | switch (byte_size) { 642 | case 1: 643 | e->baseType = Cpp::FundamentalType::UNSIGNED_CHAR; 644 | break; 645 | case 2: 646 | e->baseType = Cpp::FundamentalType::UNSIGNED_SHORT; 647 | break; 648 | case 4: 649 | e->baseType = Cpp::FundamentalType::INT; 650 | break; 651 | case 8: 652 | e->baseType = Cpp::FundamentalType::LONG; 653 | break; 654 | default: 655 | return error(std::string("Unknown enum base type size for enum type. (Size: ").append(std::to_string(byte_size)).append(")")); 656 | break; 657 | } 658 | break; 659 | case DW_AT_element_list: 660 | if (!processElementList(attr, e, byte_size)) 661 | return error("Failed to processElementList for enum type."); 662 | break; 663 | } 664 | } 665 | 666 | return true; 667 | } 668 | 669 | bool processElementList(Dwarf::Attribute *attr, Cpp::EnumType *e, int byte_size) 670 | { 671 | Dwarf *dwarf = attr->dwarf; 672 | 673 | char *block = attr->getBlock(); 674 | char *end = block + attr->size; 675 | 676 | while (block < end) 677 | { 678 | Cpp::EnumType::Element element; 679 | 680 | if (byte_size == 1) { 681 | element.constValue = dwarf->read(block); 682 | } 683 | else if (byte_size == 2) { 684 | element.constValue = dwarf->read(block); 685 | } 686 | else if (byte_size == 4) { 687 | element.constValue = dwarf->read(block); 688 | } 689 | else if (byte_size == 8) { 690 | element.constValue = dwarf->read(block); 691 | } 692 | 693 | block += byte_size; 694 | 695 | element.name = block; 696 | block += element.name.size() + 1; 697 | 698 | e->elements.push_back(element); 699 | } 700 | 701 | return true; 702 | } 703 | 704 | bool processFunctionType(Dwarf::Entry *entry, Cpp::FunctionType *f) 705 | { 706 | Dwarf::Entry *next = entry->getSibling(); 707 | Dwarf::Entry *first = entry; 708 | 709 | int paramCount = 0; 710 | entry++; 711 | 712 | while (entry && entry < next) 713 | { 714 | if (entry->tag == DW_TAG_formal_parameter) 715 | paramCount++; 716 | 717 | entry = entry->getSibling(); 718 | } 719 | 720 | f->parameters.reserve(paramCount); 721 | entry = first; 722 | 723 | size_t numAttributes = entry->attributes.size(); 724 | 725 | for (size_t i = 0; i < numAttributes; i++) 726 | { 727 | Dwarf::Attribute *attr = &entry->attributes[i]; 728 | 729 | switch (attr->name) 730 | { 731 | case DW_AT_fund_type: 732 | case DW_AT_user_def_type: 733 | case DW_AT_mod_fund_type: 734 | case DW_AT_mod_u_d_type: 735 | if (!processTypeAttr(attr, &f->returnType)) 736 | return error("Failed to processTypeAttr for function return type."); 737 | break; 738 | } 739 | } 740 | 741 | entry++; 742 | 743 | while (entry && entry < next) 744 | { 745 | switch (entry->tag) 746 | { 747 | case DW_TAG_formal_parameter: 748 | Cpp::FunctionType::Parameter p; 749 | 750 | if (!processParameter(entry, &p)) 751 | return error("Failed to processParameter for function parameter."); 752 | 753 | f->parameters.push_back(p); 754 | } 755 | 756 | entry = entry->getSibling(); 757 | } 758 | 759 | return true; 760 | } 761 | 762 | bool processParameter(Dwarf::Entry *entry, Cpp::FunctionType::Parameter *p) 763 | { 764 | size_t numAttributes = entry->attributes.size(); 765 | 766 | for (size_t i = 0; i < numAttributes; i++) 767 | { 768 | Dwarf::Attribute *attr = &entry->attributes[i]; 769 | 770 | switch (attr->name) 771 | { 772 | case DW_AT_name: 773 | p->name = attr->getString(); 774 | break; 775 | case DW_AT_fund_type: 776 | case DW_AT_user_def_type: 777 | case DW_AT_mod_fund_type: 778 | case DW_AT_mod_u_d_type: 779 | if (!processTypeAttr(attr, &p->type)) 780 | return error(std::string("Failed to processTypeAttr for parameter '").append(p->name).append("'.")); 781 | break; 782 | } 783 | } 784 | 785 | return true; 786 | } 787 | 788 | bool processFunction(Dwarf::Entry *entry, Cpp::Function *f) 789 | { 790 | f->isGlobal = (entry->tag == DW_TAG_global_subroutine); 791 | 792 | size_t numAttributes = entry->attributes.size(); 793 | 794 | for (size_t i = 0; i < numAttributes; i++) 795 | { 796 | Dwarf::Attribute *attr = &entry->attributes[i]; 797 | 798 | switch (attr->name) 799 | { 800 | case DW_AT_name: 801 | f->name = attr->getString(); 802 | break; 803 | case DW_AT_mangled_name: 804 | f->mangledName = attr->getString(); 805 | break; 806 | case DW_AT_low_pc: 807 | f->startAddress = attr->getAddress(); 808 | break; 809 | } 810 | } 811 | 812 | Dwarf::Entry *next = entry->getSibling(); 813 | 814 | entry++; 815 | 816 | while (entry && entry < next) 817 | { 818 | switch (entry->tag) 819 | { 820 | case DW_TAG_lexical_block: 821 | if (!processLexicalBlock(entry, f)) 822 | return error(std::string("Failed to processLexicalBlock for function '").append(f->name).append("'.")); 823 | } 824 | 825 | entry = entry->getSibling(); 826 | } 827 | 828 | f->typeOwner = nullptr; 829 | if (f->parameters.size() > 0 && f->parameters[0].name.compare("this") == 0) { 830 | f->typeOwner = f->parameters[0].type.userType; 831 | f->parameters.erase(f->parameters.begin()); 832 | f->typeOwner->classData->functions.push_back(*f); 833 | } 834 | else if (f->mangledName.size() > 2) { 835 | int foundAt = f->mangledName.rfind("__"); 836 | if (foundAt != -1) { 837 | char temp; 838 | std::stringstream length; 839 | int i; 840 | for (i = foundAt + 1; i < f->mangledName.size(); i++) { 841 | temp = f->mangledName[i]; 842 | if (temp >= '0' && temp <= '9') { 843 | length << temp; 844 | } 845 | else { 846 | break; 847 | } 848 | } 849 | 850 | std::string lengthStr = length.str(); 851 | if (lengthStr.length() > 0) { 852 | int lengthCount = std::stoi(lengthStr); 853 | if (f->mangledName[i + lengthCount] == 'F') { 854 | std::string className = f->mangledName.substr(i, lengthCount); 855 | 856 | // I tried to access this from the named map, but I couldn't for the life of me figure out how to do it. C++ is terrible, no other languages have runtime libraries that silently fail like this. The map is empty even though the code that adds elements to the map is run. Good grief. 857 | /*auto it = nameUTListPairs.find(className); 858 | if (it != nameUTListPairs.end()) { 859 | std::vector vector = it->second; 860 | if (vector.size() != 1) 861 | std::cout << "Couldn't find good type for '" << className << "'. (" << vector.size() << ")" << std::endl; 862 | } 863 | else { 864 | std::cout << "Couldn't find good type for '" << className << "'." << std::endl; 865 | }*/ 866 | 867 | 868 | Cpp::UserType* type = nullptr; 869 | for (std::map::iterator iter = entryUTPairs.begin(); iter != entryUTPairs.end(); ++iter) 870 | { 871 | Dwarf::Entry* k = iter->first; 872 | Cpp::UserType* value = iter->second; 873 | if (value->name.compare(className) == 0) { 874 | type = value; 875 | break; 876 | } 877 | } 878 | 879 | if (type != nullptr) { 880 | f->typeOwner = type; 881 | f->typeOwner->classData->functions.push_back(*f); 882 | } 883 | } 884 | } 885 | } 886 | } 887 | 888 | return true; 889 | } 890 | 891 | bool processLexicalBlock(Dwarf::Entry *entry, Cpp::Function *f) 892 | { 893 | Dwarf::Entry *next = entry->getSibling(); 894 | 895 | entry++; 896 | 897 | while (entry && entry < next) 898 | { 899 | switch (entry->tag) 900 | { 901 | case DW_TAG_global_variable: 902 | case DW_TAG_local_variable: 903 | { 904 | Cpp::Variable v; 905 | 906 | if (!processVariable(entry, &v)) 907 | return error(std::string("Failed to processVariable for local var lexical block in function '").append(f->name).append("'.")); 908 | 909 | f->variables.push_back(v); 910 | break; 911 | } 912 | } 913 | 914 | entry = entry->getSibling(); 915 | } 916 | 917 | return true; 918 | } 919 | 920 | bool processArrayType(Dwarf::Entry *entry, Cpp::ArrayType *a) 921 | { 922 | size_t numAttributes = entry->attributes.size(); 923 | 924 | for (size_t i = 0; i < numAttributes; i++) 925 | { 926 | Dwarf::Attribute *attr = &entry->attributes[i]; 927 | 928 | switch (attr->name) 929 | { 930 | case DW_AT_ordering: 931 | if (attr->getHword() != DW_ORD_row_major) // meh 932 | return error(std::string("processArrayType encountered ordering unsupported by dwarf2cpp! (").append(toHexString(attr->getHword())).append(")")); 933 | break; 934 | case DW_AT_subscr_data: 935 | if (!processSubscriptData(attr, a)) 936 | return error("Failed to processSubscriptData."); 937 | } 938 | } 939 | 940 | return true; 941 | } 942 | 943 | bool processSubscriptData(Dwarf::Attribute *attr, Cpp::ArrayType *a) 944 | { 945 | Dwarf *dwarf = attr->dwarf; 946 | 947 | char *block = attr->getBlock(); 948 | char *end = block + attr->size; 949 | 950 | while (block < end) 951 | { 952 | char format = dwarf->read(block); 953 | block += sizeof(char); 954 | 955 | if (format == DW_FMT_ET) 956 | { 957 | int typeAttrIndex; 958 | Dwarf::Attribute *typeAttr; 959 | Dwarf::Entry* entry = &dwarf->entries[attr->entryIndex]; 960 | Elf32_Off offset = dwarf->pointerToOffset(block); 961 | 962 | offset = dwarf->readAttribute(offset, entry, &typeAttrIndex); 963 | block = dwarf->offsetToPointer(offset); 964 | 965 | typeAttr = &entry->attributes[typeAttrIndex]; 966 | 967 | if (!processTypeAttr(typeAttr, &a->type)) 968 | return error("Failed to processTypeAttr for subscript data DW_FMT_ET."); 969 | 970 | break; 971 | } 972 | else if (format == DW_FMT_FT_C_C) 973 | { 974 | Elf32_Half fundType = dwarf->read(block); 975 | block += sizeof(Elf32_Half); 976 | 977 | // Only long indices are supported 978 | if (fundType != DW_FT_long) 979 | return error(std::string("Subscript data DW_FMT_FT_C_C had unsupported fundamental indice type ").append(toHexString(fundType)).append(" in type '").append(a->toNameString("")).append("'.")); 980 | 981 | Elf32_Word lowBound = dwarf->read(block); 982 | block += sizeof(Elf32_Word); 983 | 984 | // Only indices starting at 0 are supported 985 | if (lowBound != 0) 986 | return error(std::string("Subscript data contained indices which did not start at zero! (Start at: '").append(toHexString(lowBound)).append("', Type: '").append(a->toNameString("")).append("')")); 987 | 988 | Elf32_Word highBound = dwarf->read(block); 989 | block += sizeof(Elf32_Word); 990 | 991 | Cpp::ArrayType::Dimension dimension; 992 | dimension.size = highBound + 1; 993 | 994 | a->dimensions.push_back(dimension); 995 | } 996 | else 997 | { 998 | // Only fundamental typed (long) indices and 999 | // constant value bounds are supported 1000 | return error(std::string("Encountered subscript data format unsupported by dwarf2cpp! (").append(toHexString(format)).append(")")); 1001 | } 1002 | } 1003 | 1004 | return true; 1005 | } 1006 | 1007 | void replaceChar(char *str, char ch, char newCh) 1008 | { 1009 | char *end = str + strlen(str); 1010 | 1011 | while (str < end) 1012 | { 1013 | if (*str == ch) 1014 | *str = newCh; 1015 | str++; 1016 | } 1017 | } 1018 | --------------------------------------------------------------------------------