├── .gitignore ├── CFG_reconstructor.py ├── LICENSE ├── Locals.props ├── Paper.pdf ├── README.md ├── icount ├── MyPinTool.sln ├── MyPinTool.vcxproj ├── MyPinTool.vcxproj.filters ├── MyPinTool.vcxproj.user ├── Win32 │ └── Debug │ │ └── MyPinTool.log ├── callbacks.cpp ├── callbacks.h ├── constants.h ├── dump.cpp ├── dump.h ├── error_handlers.h ├── flusher.cpp ├── flusher.h ├── json.cpp ├── json.h ├── loggers.h ├── main.cpp ├── main.h ├── offline_flushed.cpp ├── proc.h ├── report.cpp ├── report.h └── utils.h ├── performance_parser.py ├── pintools.sln └── tester.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | # Spare 2 | idapython 3 | .vs 4 | .vscode 5 | CFG.gv* 6 | 7 | # Byte-compiled / optimized / DLL files 8 | __pycache__/ 9 | *.py[cod] 10 | *$py.class 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | build/ 18 | develop-eggs/ 19 | dist/ 20 | downloads/ 21 | eggs/ 22 | .eggs/ 23 | lib/ 24 | lib64/ 25 | parts/ 26 | sdist/ 27 | var/ 28 | wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | MANIFEST 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *.cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # pyenv 82 | .python-version 83 | 84 | # celery beat schedule file 85 | celerybeat-schedule 86 | 87 | # SageMath parsed files 88 | *.sage.py 89 | 90 | # Environments 91 | .env 92 | .venv 93 | env/ 94 | venv/ 95 | ENV/ 96 | env.bak/ 97 | venv.bak/ 98 | 99 | # Spyder project settings 100 | .spyderproject 101 | .spyproject 102 | 103 | # Rope project settings 104 | .ropeproject 105 | 106 | # mkdocs documentation 107 | /site 108 | 109 | # mypy 110 | .mypy_cache/ 111 | 112 | # Prerequisites 113 | *.d 114 | 115 | # Compiled Object files 116 | *.slo 117 | *.lo 118 | *.o 119 | *.obj 120 | 121 | # Precompiled Headers 122 | *.gch 123 | *.pch 124 | 125 | # Compiled Dynamic libraries 126 | *.so 127 | *.dylib 128 | *.dll 129 | 130 | # Fortran module files 131 | *.mod 132 | *.smod 133 | 134 | # Compiled Static libraries 135 | *.lai 136 | *.la 137 | *.a 138 | *.lib 139 | 140 | # Executables 141 | *.exe 142 | *.out 143 | *.app 144 | 145 | # Visual Studio 146 | .vs/ 147 | ## Ignore Visual Studio temporary files, build results, and 148 | ## files generated by popular Visual Studio add-ons. 149 | ## 150 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 151 | 152 | # User-specific files 153 | *.suo 154 | *.user 155 | *.userosscache 156 | *.sln.docstates 157 | 158 | # User-specific files (MonoDevelop/Xamarin Studio) 159 | *.userprefs 160 | 161 | # Build results 162 | [Dd]ebug/ 163 | [Dd]ebugPublic/ 164 | [Rr]elease/ 165 | [Rr]eleases/ 166 | x64/ 167 | x86/ 168 | bld/ 169 | [Bb]in/ 170 | [Oo]bj/ 171 | [Ll]og/ 172 | 173 | # Visual Studio 2015/2017 cache/options directory 174 | .vs/ 175 | # Uncomment if you have tasks that create the project's static files in wwwroot 176 | #wwwroot/ 177 | 178 | # Visual Studio 2017 auto generated files 179 | Generated\ Files/ 180 | 181 | # MSTest test Results 182 | [Tt]est[Rr]esult*/ 183 | [Bb]uild[Ll]og.* 184 | 185 | # NUNIT 186 | *.VisualState.xml 187 | TestResult.xml 188 | 189 | # Build Results of an ATL Project 190 | [Dd]ebugPS/ 191 | [Rr]eleasePS/ 192 | dlldata.c 193 | 194 | # Benchmark Results 195 | BenchmarkDotNet.Artifacts/ 196 | 197 | # .NET Core 198 | project.lock.json 199 | project.fragment.lock.json 200 | artifacts/ 201 | 202 | # StyleCop 203 | StyleCopReport.xml 204 | 205 | # Files built by Visual Studio 206 | *_i.c 207 | *_p.c 208 | *_i.h 209 | *.ilk 210 | *.meta 211 | *.obj 212 | *.iobj 213 | *.pch 214 | *.pdb 215 | *.ipdb 216 | *.pgc 217 | *.pgd 218 | *.rsp 219 | *.sbr 220 | *.tlb 221 | *.tli 222 | *.tlh 223 | *.tmp 224 | *.tmp_proj 225 | *.log 226 | *.vspscc 227 | *.vssscc 228 | .builds 229 | *.pidb 230 | *.svclog 231 | *.scc 232 | 233 | # Chutzpah Test files 234 | _Chutzpah* 235 | 236 | # Visual C++ cache files 237 | ipch/ 238 | *.aps 239 | *.ncb 240 | *.opendb 241 | *.opensdf 242 | *.sdf 243 | *.cachefile 244 | *.VC.db 245 | *.VC.VC.opendb 246 | 247 | # Visual Studio profiler 248 | *.psess 249 | *.vsp 250 | *.vspx 251 | *.sap 252 | 253 | # Visual Studio Trace Files 254 | *.e2e 255 | 256 | # TFS 2012 Local Workspace 257 | $tf/ 258 | 259 | # Guidance Automation Toolkit 260 | *.gpState 261 | 262 | # ReSharper is a .NET coding add-in 263 | _ReSharper*/ 264 | *.[Rr]e[Ss]harper 265 | *.DotSettings.user 266 | 267 | # JustCode is a .NET coding add-in 268 | .JustCode 269 | 270 | # TeamCity is a build add-in 271 | _TeamCity* 272 | 273 | # DotCover is a Code Coverage Tool 274 | *.dotCover 275 | 276 | # AxoCover is a Code Coverage Tool 277 | .axoCover/* 278 | !.axoCover/settings.json 279 | 280 | # Visual Studio code coverage results 281 | *.coverage 282 | *.coveragexml 283 | 284 | # NCrunch 285 | _NCrunch_* 286 | .*crunch*.local.xml 287 | nCrunchTemp_* 288 | 289 | # MightyMoose 290 | *.mm.* 291 | AutoTest.Net/ 292 | 293 | # Web workbench (sass) 294 | .sass-cache/ 295 | 296 | # Installshield output folder 297 | [Ee]xpress/ 298 | 299 | # DocProject is a documentation generator add-in 300 | DocProject/buildhelp/ 301 | DocProject/Help/*.HxT 302 | DocProject/Help/*.HxC 303 | DocProject/Help/*.hhc 304 | DocProject/Help/*.hhk 305 | DocProject/Help/*.hhp 306 | DocProject/Help/Html2 307 | DocProject/Help/html 308 | 309 | # Click-Once directory 310 | publish/ 311 | 312 | # Publish Web Output 313 | *.[Pp]ublish.xml 314 | *.azurePubxml 315 | # Note: Comment the next line if you want to checkin your web deploy settings, 316 | # but database connection strings (with potential passwords) will be unencrypted 317 | *.pubxml 318 | *.publishproj 319 | 320 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 321 | # checkin your Azure Web App publish settings, but sensitive information contained 322 | # in these scripts will be unencrypted 323 | PublishScripts/ 324 | 325 | # NuGet Packages 326 | *.nupkg 327 | # The packages folder can be ignored because of Package Restore 328 | **/[Pp]ackages/* 329 | # except build/, which is used as an MSBuild target. 330 | !**/[Pp]ackages/build/ 331 | # Uncomment if necessary however generally it will be regenerated when needed 332 | #!**/[Pp]ackages/repositories.config 333 | # NuGet v3's project.json files produces more ignorable files 334 | *.nuget.props 335 | *.nuget.targets 336 | 337 | # Microsoft Azure Build Output 338 | csx/ 339 | *.build.csdef 340 | 341 | # Microsoft Azure Emulator 342 | ecf/ 343 | rcf/ 344 | 345 | # Windows Store app package directories and files 346 | AppPackages/ 347 | BundleArtifacts/ 348 | Package.StoreAssociation.xml 349 | _pkginfo.txt 350 | *.appx 351 | 352 | # Visual Studio cache files 353 | # files ending in .cache can be ignored 354 | *.[Cc]ache 355 | # but keep track of directories ending in .cache 356 | !*.[Cc]ache/ 357 | 358 | # Others 359 | ClientBin/ 360 | ~$* 361 | *~ 362 | *.dbmdl 363 | *.dbproj.schemaview 364 | *.jfm 365 | *.pfx 366 | *.publishsettings 367 | orleans.codegen.cs 368 | 369 | # Including strong name files can present a security risk 370 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 371 | #*.snk 372 | 373 | # Since there are multiple workflows, uncomment next line to ignore bower_components 374 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 375 | #bower_components/ 376 | 377 | # RIA/Silverlight projects 378 | Generated_Code/ 379 | 380 | # Backup & report files from converting an old project file 381 | # to a newer Visual Studio version. Backup files are not needed, 382 | # because we have git ;-) 383 | _UpgradeReport_Files/ 384 | Backup*/ 385 | UpgradeLog*.XML 386 | UpgradeLog*.htm 387 | ServiceFabricBackup/ 388 | *.rptproj.bak 389 | 390 | # SQL Server files 391 | *.mdf 392 | *.ldf 393 | *.ndf 394 | 395 | # Business Intelligence projects 396 | *.rdl.data 397 | *.bim.layout 398 | *.bim_*.settings 399 | *.rptproj.rsuser 400 | 401 | # Microsoft Fakes 402 | FakesAssemblies/ 403 | 404 | # GhostDoc plugin setting file 405 | *.GhostDoc.xml 406 | 407 | # Node.js Tools for Visual Studio 408 | .ntvs_analysis.dat 409 | node_modules/ 410 | 411 | # Visual Studio 6 build log 412 | *.plg 413 | 414 | # Visual Studio 6 workspace options file 415 | *.opt 416 | 417 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 418 | *.vbw 419 | 420 | # Visual Studio LightSwitch build output 421 | **/*.HTMLClient/GeneratedArtifacts 422 | **/*.DesktopClient/GeneratedArtifacts 423 | **/*.DesktopClient/ModelManifest.xml 424 | **/*.Server/GeneratedArtifacts 425 | **/*.Server/ModelManifest.xml 426 | _Pvt_Extensions 427 | 428 | # Paket dependency manager 429 | .paket/paket.exe 430 | paket-files/ 431 | 432 | # FAKE - F# Make 433 | .fake/ 434 | 435 | # JetBrains Rider 436 | .idea/ 437 | *.sln.iml 438 | 439 | # CodeRush 440 | .cr/ 441 | 442 | # Python Tools for Visual Studio (PTVS) 443 | __pycache__/ 444 | *.pyc 445 | 446 | # Cake - Uncomment if you are using it 447 | # tools/** 448 | # !tools/packages.config 449 | 450 | # Tabs Studio 451 | *.tss 452 | 453 | # Telerik's JustMock configuration file 454 | *.jmconfig 455 | 456 | # BizTalk build output 457 | *.btp.cs 458 | *.btm.cs 459 | *.odx.cs 460 | *.xsd.cs 461 | 462 | # OpenCover UI analysis results 463 | OpenCover/ 464 | 465 | # Azure Stream Analytics local run output 466 | ASALocalRun/ 467 | 468 | # MSBuild Binary and Structured Log 469 | *.binlog 470 | 471 | # NVidia Nsight GPU debugger configuration file 472 | *.nvuser 473 | 474 | # MFractors (Xamarin productivity tool) working folder 475 | .mfractor/ 476 | 477 | # Pin 478 | pin.log 479 | *.db 480 | *opendb 481 | -------------------------------------------------------------------------------- /CFG_reconstructor.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from graphviz import Digraph 4 | from capstone import * 5 | from collections import namedtuple 6 | 7 | TRACE_LIMIT = 9999999 8 | 9 | dot = Digraph(comment="Alamanas") 10 | dot.attr('node', shape='box') 11 | 12 | md = Cs(CS_ARCH_X86, CS_MODE_32) 13 | Instruction = namedtuple('Instruction', 'address disasm') 14 | 15 | global report, images, sections 16 | report = {} 17 | images = {} 18 | sections = {} 19 | 20 | main_image = '' 21 | text_instr = [] 22 | global text_low, text_high, text_section 23 | text_low = 0x0 24 | text_high = 0x0 25 | text_section = '' 26 | 27 | # Trying to understand why some parts are not found 28 | global intervals 29 | intervals = [] 30 | def updateIntervals(a, b): 31 | global intervals 32 | found = False 33 | for i in intervals: 34 | if i[0] <= a <= i[1]: 35 | found = True 36 | if b > i[1]: 37 | i[1] = b 38 | 39 | if i[0] <= b <= i[1]: 40 | found = True 41 | if a < i[0]: 42 | i[0] = a 43 | if not found: 44 | intervals += [[a, b]] 45 | 46 | def load_report(): 47 | global report, images, sections 48 | global text_low, text_high, text_section 49 | with open("report.json") as f: 50 | report = json.load(f) 51 | 52 | images = report["images"] 53 | main_image = report["main_image"] 54 | 55 | sections = report["sections"] 56 | text_section = report['text_section'] 57 | text_low = sections[text_section]['address'] 58 | text_size = sections[text_section]['size'] 59 | text_low = text_low 60 | text_size = text_size 61 | text_high = text_low + text_size 62 | 63 | def disasm_text_section(): 64 | global text_low, text_high, text_section 65 | instructions = [] 66 | disasm_file = open("TEXT.disasm", "w+") 67 | with open(text_section + '.dump', 'rb') as f: 68 | for i in md.disasm(f.read(), text_low): 69 | instructions += [Instruction(address=(i.address), disasm=i.mnemonic + ' ' + i.op_str)] 70 | print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str), file=disasm_file) 71 | return instructions 72 | 73 | def getDisasmInRange(a:int, b:int): 74 | instructions = [] 75 | if (a > b) : 76 | print('Switched intervals {} {}'.format(a, b)) 77 | for i in text_instr: 78 | if a <= i.address < b: 79 | instructions += [i.disasm] 80 | if len(instructions) == 0: 81 | # print('Nothing found from {} to {}'.format(hex(a), hex(b))) 82 | updateIntervals(min(a, b), max(a, b)) 83 | return instructions 84 | 85 | def insertExternalStub(last_ip:str): 86 | found = False 87 | for name, mem_range in images.items(): 88 | if mem_range['low_address'] <= int(last_ip, 16) <= mem_range['high_address']: 89 | found = True 90 | short_name = name[name.rfind('\\')+1:] 91 | dot.node(last_ip, label=short_name, shape='ellipse') 92 | if not found: 93 | dot.node(last_ip, label='Stub', shape='ellipse') 94 | 95 | def parse_trace(): 96 | with open('trace_0.out') as f: 97 | lines_no = 0 98 | edges = set() 99 | last_ip = '0x0' 100 | for line in f: 101 | # Cleanup the string 102 | line = line.replace('\x00', '').strip() 103 | if len(line) == 0: 104 | continue 105 | 106 | ip, target = line.split('@') 107 | # Very first instruction 108 | if ip == '': 109 | last_ip = target 110 | continue 111 | 112 | if not (text_low <= int(last_ip, 16) <= text_high): 113 | insertExternalStub(last_ip) 114 | else: 115 | instr_in_range = getDisasmInRange(int(last_ip, 16), int(ip, 16)) 116 | dot.node(last_ip, label='\n'.join(instr_in_range)) 117 | edges.add((last_ip, target)) 118 | last_ip = target 119 | 120 | if lines_no >= TRACE_LIMIT: 121 | break 122 | lines_no += 1 123 | 124 | dot.edges(list(edges)) 125 | 126 | 127 | if __name__ == "__main__": 128 | load_report() 129 | text_instr = disasm_text_section() 130 | parse_trace() 131 | dot.render('CFG.gv', view=True) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Andrea Tulimiero 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Locals.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | C:\Pin35 6 | 7 | 8 | <_PropertySheetDisplayName>Locals 9 | 10 | 11 | 12 | 13 | $(PinFolder) 14 | 15 | 16 | -------------------------------------------------------------------------------- /Paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreatulimiero/PinCFGReconstructor/eaa3b913321aa17505a5af718873dbec1482d45b/Paper.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PinCFGReconstructor 2 | 3 | ## TL;DR 4 | An efficient Pintool to reconstruct the Control Flow Graph (CFG) of plain and UPX packed executables. 5 | 6 | ## Abstract 7 | With the development of increasingly advanced techniques to hide the malicious 8 | payload of a Malware, the community of reverse engineers and security researchers 9 | has been facing more and more complex programs which brought about the need of 10 | more advanced analysis than classic ones based on static code inspection. To truly 11 | understand what such malicious programs do, an analyst needs to look at them 12 | while they are executing, thus tools to carry out their analyses at runtime have 13 | become one of the most powerful weapons to face new threats. 14 | Among the techniques for the design and implementation of such tools there is 15 | dynamic binary instrumentation (DBI), an advanced solution that makes it possible 16 | to instrument a program dynamically (i.e., while it is running), allowing for a 17 | fine-grained inspection of its execution. Although this technique is very powerful, 18 | it carries with it some performance and accuracy trade-offs. In this project we will 19 | build tools to record instructions and reconstruct the control flow graph of a possibly 20 | malicious program, discussing during the journey the challenges introduced by the 21 | usage of DBI and proposing some solutions to mitigate these problems. 22 | 23 | ## Dependencies 24 | - [Intel PIN](https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.5-97503-gac534ca30-msvc-windows.zip) 25 | - [Capstone](https://www.capstone-engine.org/download.html) 26 | - [Graphviz](https://www.graphviz.org/download) 27 | - [Python 3.6.3](https://www.python.org/downloads/release/python-363) 28 | - The solution has been compiled using Visual Studio 2010 (v100) toolset. I strongly advise to install [Visual C++ 2010 Express Edition](https://my.visualstudio.com/Downloads?q=visual%20studio%202010&wt.mc_id=o~msft~vscom~older-downloads) (to get the toolset), and then using Visual Studio 2015 or later IDE. 29 | 30 | ## Usage 31 | Assuming Intel Pin folder is located at `C:\Pin35`, you can launch the tool with the following structure: 32 | `C:\Pin35\pin.exe -t C:\Pin35\icount.dll -- ` 33 | By default the tool uses the Unbuffered version and generates a trace of 2Gb maximum 34 | Once the tool finishes instrumenting the executable it generates: a (i)`trace.out` file; a (ii)dump of each of the sections of the program; and a (iii) `report.json` file containing information about the executed programs (e.g.: Sections' low addresses and size). 35 | Once the analysis is finished, the CFG can be reconstructed by launching `python CFG_reconstructor.py`. A PDF of the CFG will be shown and a file called CFG.gv.pdf will be created 36 | 37 | #### Pintool otions 38 | Apart from the standard switches of Intel Pin, the Pintool can be configured with these additional switches: 39 | - -**buffered** [default false]: 40 | whether or not the trace is buffered 41 | - -**thread_flushed** [default false]: 42 | whether or not the trace has a thread for flushing 43 | - -**favor_main_thread** [default false]: 44 | allocate only a quarter of thread buffer for threads that are not the main one 45 | - -**tag** [default ""]: 46 | tag for the performance report. If missing no report will be generated 47 | - -**thread_buffer_size** [default 30Mb]: 48 | size of the per-thread buffer 49 | - -**trace_limit** [default 2Gb]: 50 | size of the trace limit 51 | 52 | ### Notes 53 | The tool has been tested on Win32 only with UPX packer. 54 | 55 | ## Thanks 56 | This work has also been possible thanks to: [Capstone](https://github.com/aquynh/capstone) and [Graphviz](https://gitlab.com/graphviz/graphviz) 57 | -------------------------------------------------------------------------------- /icount/MyPinTool.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyPinTool", "MyPinTool.vcxproj", "{639EF517-FCFC-408E-9500-71F0DC0458DB}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Debug|Win32.Build.0 = Debug|Win32 16 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Debug|x64.ActiveCfg = Debug|x64 17 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Debug|x64.Build.0 = Debug|x64 18 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Release|Win32.ActiveCfg = Release|Win32 19 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Release|Win32.Build.0 = Release|Win32 20 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Release|x64.ActiveCfg = Release|x64 21 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /icount/MyPinTool.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {639EF517-FCFC-408E-9500-71F0DC0458DB} 23 | MyPinTool 24 | Win32Proj 25 | icount 26 | 27 | 28 | 29 | DynamicLibrary 30 | MultiByte 31 | true 32 | v100 33 | 34 | 35 | DynamicLibrary 36 | MultiByte 37 | true 38 | v100 39 | 40 | 41 | DynamicLibrary 42 | MultiByte 43 | true 44 | v100 45 | 46 | 47 | DynamicLibrary 48 | MultiByte 49 | true 50 | v100 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | <_ProjectFileVersion>10.0.40219.1 74 | $(PinFolder)\ 75 | $(PinFolder)\ 76 | $(Platform)\$(Configuration)\ 77 | $(Platform)\$(Configuration)\ 78 | $(Platform)\$(Configuration)\ 79 | $(Platform)\$(Configuration)\ 80 | false 81 | false 82 | false 83 | false 84 | false 85 | false 86 | false 87 | false 88 | AllRules.ruleset 89 | AllRules.ruleset 90 | AllRules.ruleset 91 | AllRules.ruleset 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | $(PinFolder)\intel64\lib;$(PinFolder)\intel64\runtime\pincrt;$(PinFolder\extras\xed-intel64;$(LibraryPath) 101 | $(WindowsSdkDir)\lib 102 | $(WindowsSdkDir)\lib\x64 103 | $(WindowsSdkDir)\lib 104 | 105 | 106 | $(PinFolder)\ 107 | $(ProjectName)32 108 | 109 | 110 | $(PinFolder)\ 111 | $(ProjectName)32 112 | 113 | 114 | $(ProjectName)64 115 | 116 | 117 | 118 | X64 119 | 120 | 121 | /EHs- /EHa- %(AdditionalOptions) 122 | true 123 | false 124 | $(PinFolder)\source\include\pin;$(PinFolder)\source\include\pin\gen;$(PinFolder)\extras\stlport\include;$(PinFolder)\extras;$(PinFolder)\extras\libstdc++\include;$(PinFolder)\extras\crt\include;$(PinFolder)\extras\crt;$(PinFolder)\extras\crt\include\arch-x86_64;$(PinFolder)\extras\components\include;$(PinFolder)\extras\crt\include\kernel\uapi;$(PinFolder)\extras\crt\include\kernel\uapi\asm-x86;$(PinFolder)\extras\xed-intel64\include\xed;$(AdditionalIncludeDirectories) 125 | TARGET_IA32E;__LP64__;HOST_IA32E;__PIN__=1;PIN_CRT=1;TARGET_WINDOWS;BIGARRAY_MULTIPLIER=1;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0;WIN32;_WINDOWS_H_PATH_=$(WindowsSdkDir)\Include;_PIN_FOLDER="$(PinFolder)" 126 | false 127 | 128 | 129 | Default 130 | MultiThreaded 131 | false 132 | true 133 | false 134 | 135 | 136 | Level3 137 | 138 | 139 | 4005;4530;%(DisableSpecificWarnings) 140 | include/msvc_compat.h 141 | false 142 | 143 | 144 | /export:main /ignore:4210 /ignore:4049 %(AdditionalOptions) 145 | $(PinFolder)\intel64\runtime\pincrt\crtbeginS.obj;pin.lib;xed.lib;pinvm.lib;stlport-static.lib;m-static.lib;c-static.lib;os-apis.lib;ntdll-64.lib;kernel32.lib;%(AdditionalDependencies) 146 | $(PinFolder)\intel64\lib;$(PinFolder)\intel64\lib-ext;$(PinFolder)\extras\xed-intel64\lib;%(AdditionalLibraryDirectories) 147 | true 148 | %(IgnoreSpecificDefaultLibraries) 149 | true 150 | NotSet 151 | true 152 | 153 | 154 | 155 | 156 | Ptrace_DllMainCRTStartup 157 | 0xC5000000 158 | MachineX64 159 | false 160 | 161 | 162 | 163 | 164 | 165 | /EHs- /EHa- %(AdditionalOptions) 166 | true 167 | false 168 | $(PinFolder)\source\include\pin;$(PinFolder)\source\include\pin\gen;$(PinFolder)\extras\stlport\include;$(PinFolder)\extras;$(PinFolder)\extras\libstdc++\include;$(PinFolder)\extras\crt\include;$(PinFolder)\extras\crt;$(PinFolder)\extras\crt\include\kernel\uapi;$(PinFolder)\extras\crt\include\kernel\uapi\asm-x86;$(PinFolder)\extras\components\include;$(PinFolder)\extras\crt\include\arch-x86;$(PinFolder)\extras\xed-ia32\include\xed 169 | TARGET_IA32;__i386__;HOST_IA32;__PIN__=1;PIN_CRT=1;TARGET_WINDOWS;BIGARRAY_MULTIPLIER=1;USING_XED;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0;WIN32;_WINDOWS_H_PATH_=$(WindowsSdkDir)\Include;_PIN_FOLDER="$(PinFolder)" 170 | false 171 | 172 | 173 | Default 174 | MultiThreaded 175 | false 176 | true 177 | false 178 | 179 | 180 | Level3 181 | 182 | 183 | 4005;4530;%(DisableSpecificWarnings) 184 | include/msvc_compat.h 185 | false 186 | 187 | 188 | /export:main /ignore:4210 /ignore:4049 %(AdditionalOptions) 189 | $(PinFolder)\ia32\runtime\pincrt\crtbeginS.obj;pin.lib;xed.lib;pinvm.lib;stlport-static.lib;m-static.lib;c-static.lib;os-apis.lib;ntdll-32.lib;kernel32.lib;%(AdditionalDependencies) 190 | $(PinFolder)\ia32\lib;$(PinFolder)\ia32\lib-ext;$(PinFolder)\ia32\runtime\pincrt\;$(PinFolder)\extras\xed-ia32\lib;%(AdditionalLibraryDirectories) 191 | true 192 | %(IgnoreSpecificDefaultLibraries) 193 | true 194 | NotSet 195 | true 196 | 197 | 198 | 199 | 200 | Ptrace_DllMainCRTStartup%4012 201 | 0x55000000 202 | false 203 | 204 | 205 | 206 | 207 | X64 208 | 209 | 210 | /EHs- /EHa- %(AdditionalOptions) 211 | false 212 | false 213 | $(PinFolder)\source\include\pin;$(PinFolder)\source\include\pin\gen;$(PinFolder)\extras\stlport\include;$(PinFolder)\extras;$(PinFolder)\extras\libstdc++\include;$(PinFolder)\extras\crt\include;$(PinFolder)\extras\crt;$(PinFolder)\extras\crt\include\arch-x86_64;$(PinFolder)\extras\components\include;$(PinFolder)\extras\crt\include\kernel\uapi;$(PinFolder)\extras\crt\include\kernel\uapi\asm-x86;$(PinFolder)\extras\xed-intel64\include\xed;$(AdditionalIncludeDirectories) 214 | false 215 | 216 | 217 | Default 218 | MultiThreaded 219 | false 220 | true 221 | false 222 | 223 | 224 | Level3 225 | ProgramDatabase 226 | 4005;4530;%(DisableSpecificWarnings) 227 | include/msvc_compat.h 228 | false 229 | TARGET_IA32E;__LP64__;HOST_IA32E;__PIN__=1;PIN_CRT=1;TARGET_WINDOWS;BIGARRAY_MULTIPLIER=1;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0;WIN32;_WINDOWS_H_PATH_=$(WindowsSdkDir)\Include;_PIN_FOLDER="$(PinFolder)" 230 | 231 | 232 | /export:main /ignore:4210 /ignore:4049 %(AdditionalOptions) 233 | $(PinFolder)\intel64\runtime\pincrt\crtbeginS.obj;pin.lib;xed.lib;pinvm.lib;stlport-static.lib;m-static.lib;c-static.lib;os-apis.lib;ntdll-64.lib;kernel32.lib;%(AdditionalDependencies) 234 | $(PinFolder)\intel64\lib;$(PinFolder)\intel64\lib-ext;$(PinFolder)\intel64\runtime\pincrt\;$(PinFolder)\extras\xed-intel64\lib;%(AdditionalLibraryDirectories) 235 | true 236 | %(IgnoreSpecificDefaultLibraries) 237 | true 238 | NotSet 239 | false 240 | 241 | 242 | 243 | 244 | Ptrace_DllMainCRTStartup 245 | 0xC5000000 246 | MachineX64 247 | false 248 | 249 | 250 | 251 | 252 | 253 | /EHs- /EHa- %(AdditionalOptions) 254 | false 255 | false 256 | $(PinFolder)\source\include\pin;$(PinFolder)\source\include\pin\gen;$(PinFolder)\extras\stlport\include;$(PinFolder)\extras;$(PinFolder)\extras\libstdc++\include;$(PinFolder)\extras\crt\include;$(PinFolder)\extras\crt;$(PinFolder)\extras\crt\include\kernel\uapi;$(PinFolder)\extras\crt\include\kernel\uapi\asm-x86;$(PinFolder)\extras\components\include;$(PinFolder)\extras\crt\include\arch-x86;$(PinFolder)\extras\xed-ia32\include\xed 257 | TARGET_IA32;__i386__;HOST_IA32;__PIN__=1;PIN_CRT=1;TARGET_WINDOWS;BIGARRAY_MULTIPLIER=1;USING_XED;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0;WIN32;_WINDOWS_H_PATH_=$(WindowsSdkDir)\Include;_PIN_FOLDER="$(PinFolder)" 258 | false 259 | 260 | 261 | Default 262 | MultiThreaded 263 | false 264 | true 265 | false 266 | 267 | 268 | Level3 269 | ProgramDatabase 270 | 4005;4530;%(DisableSpecificWarnings) 271 | include/msvc_compat.h 272 | false 273 | Disabled 274 | false 275 | 276 | 277 | /export:main /ignore:4210 /ignore:4049 %(AdditionalOptions) 278 | $(PinFolder)\ia32\runtime\pincrt\crtbeginS.obj;pin.lib;xed.lib;pinvm.lib;stlport-static.lib;m-static.lib;c-static.lib;os-apis.lib;ntdll-32.lib;kernel32.lib;%(AdditionalDependencies) 279 | $(PinFolder)\ia32\lib;$(PinFolder)\ia32\lib-ext;$(PinFolder)\ia32\runtime\pincrt\;$(PinFolder)\extras\xed-ia32\lib;%(AdditionalLibraryDirectories) 280 | true 281 | %(IgnoreSpecificDefaultLibraries) 282 | true 283 | NotSet 284 | false 285 | 286 | 287 | 288 | 289 | Ptrace_DllMainCRTStartup%4012 290 | 0x55000000 291 | false 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | -------------------------------------------------------------------------------- /icount/MyPinTool.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;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Header Files 16 | 17 | 18 | Header Files 19 | 20 | 21 | Header Files 22 | 23 | 24 | Header Files 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | 49 | 50 | Source Files 51 | 52 | 53 | Source Files 54 | 55 | 56 | Source Files 57 | 58 | 59 | Source Files 60 | 61 | 62 | Source Files 63 | 64 | 65 | Source Files 66 | 67 | 68 | -------------------------------------------------------------------------------- /icount/MyPinTool.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /icount/Win32/Debug/MyPinTool.log: -------------------------------------------------------------------------------- 1 |  dump.cpp 2 | main.cpp 3 | callbacks.cpp 4 | flusher.cpp 5 | json.cpp 6 | report.cpp 7 | Generating Code... 8 | c:\users\tulim\works\pincfgreconstructor\icount\json.cpp(3095): warning C4715: 'Json::Value::asString' : not all control paths return a value 9 | c:\users\tulim\works\pincfgreconstructor\icount\json.cpp(3127): warning C4715: 'Json::Value::asInt' : not all control paths return a value 10 | c:\users\tulim\works\pincfgreconstructor\icount\json.cpp(3149): warning C4715: 'Json::Value::asUInt' : not all control paths return a value 11 | c:\users\tulim\works\pincfgreconstructor\icount\json.cpp(3172): warning C4715: 'Json::Value::asInt64' : not all control paths return a value 12 | c:\users\tulim\works\pincfgreconstructor\icount\json.cpp(3193): warning C4715: 'Json::Value::asUInt64' : not all control paths return a value 13 | c:\users\tulim\works\pincfgreconstructor\icount\json.cpp(3232): warning C4715: 'Json::Value::asDouble' : not all control paths return a value 14 | c:\users\tulim\works\pincfgreconstructor\icount\json.cpp(3255): warning C4715: 'Json::Value::asFloat' : not all control paths return a value 15 | c:\users\tulim\works\pincfgreconstructor\icount\json.cpp(3274): warning C4715: 'Json::Value::asBool' : not all control paths return a value 16 | Creating library C:\Pin35\icount32.lib and object C:\Pin35\icount32.exp 17 | json.obj : warning LNK4217: locally defined symbol ___sF imported in function "private: bool __thiscall Json::OurReader::decodeString(class Json::OurReader::Token &,class std::basic_string,class std::allocator > &)" (?decodeString@OurReader@Json@@AAE_NAAVToken@12@AAV?$basic_string@DV?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 18 | main.obj : warning LNK4217: locally defined symbol ___sF imported in function "void __cdecl `dynamic initializer for 'KnobTraceLimit''(void)" (??__EKnobTraceLimit@@YAXXZ) 19 | callbacks.obj : warning LNK4217: locally defined symbol ___sF imported in function "public: static bool __cdecl LEVEL_PINCLIENT::CLIENT_TLS::IsValidTlsKey(int,unsigned int)" (?IsValidTlsKey@CLIENT_TLS@LEVEL_PINCLIENT@@SA_NHI@Z) 20 | MyPinTool.vcxproj -> C:\Pin35\icount32.dll 21 | -------------------------------------------------------------------------------- /icount/callbacks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "callbacks.h" 4 | #include "main.h" 5 | #include "constants.h" 6 | #include "loggers.h" 7 | #include "utils.h" 8 | #include "error_handlers.h" 9 | #include 10 | 11 | void INS_EntryPoint(ADDRINT ip, THREADID thread_idx) { 12 | if (IN_RANGE(ip, main_img_memory.first, main_img_memory.second) && 13 | proc_info->EP == INVALID_ENTRY_POINT) { 14 | 15 | proc_info->EP = ip; 16 | /* Allocate enough space in order to save: 17 | - @ char (1 byte) 18 | - address in hex format (sizeof(ADDRINT) * 2 bytes) for ip 19 | - 0 terminator (1 byte)*/ 20 | size_t buf_len = sizeof(ADDRINT) * 2 + 2; 21 | char* buf = (char*) malloc(buf_len); 22 | sprintf(buf, "@%08x\0", ip); 23 | 24 | trace_t* trace = (trace_t*) PIN_GetThreadData(tls_key, thread_idx); 25 | // Trace limit guard 26 | if (traceLimitGuard(trace, buf_len, thread_idx)) return; 27 | 28 | if (isBuffered) 29 | recordTraceInMemory(buf, buf_len, trace) 30 | else 31 | recordTraceToFile(files[thread_idx], buf, buf_len, trace); 32 | } 33 | } 34 | 35 | void INS_Analysis(char* buf, UINT32 buf_len, THREADID thread_idx) { 36 | trace_t* trace = (trace_t*) PIN_GetThreadData(tls_key, thread_idx); 37 | // Trace limit guard 38 | if (traceLimitGuard(trace, buf_len, thread_idx)) return; 39 | 40 | if (isBuffered) 41 | recordTraceInMemory(buf, buf_len, trace) 42 | else 43 | recordTraceToFile(files[thread_idx], buf, buf_len, trace); 44 | } 45 | 46 | void INS_JumpAnalysis(ADDRINT ins_end, ADDRINT target_branch, INT32 taken, THREADID thread_idx) { 47 | if (!taken) return; 48 | trace_t* trace = (trace_t*) PIN_GetThreadData(tls_key, thread_idx); 49 | /* Allocate enough space in order to save: 50 | - @ char (1 byte) 51 | - address in hex format (sizeof(ADDRINT) * 2) * 2 bytes for ip and target 52 | - \n delimiter (1 byte) 53 | - 0 terminator (1 byte)*/ 54 | size_t buf_len = (sizeof(ADDRINT) * 4 + 3); 55 | // Trace limit guard 56 | if (traceLimitGuard(trace, buf_len, thread_idx)) return; 57 | 58 | char* buf = (char*) malloc(sizeof(char) * buf_len); 59 | MALLOC_ERROR_HANDLER(buf, "[x] Not enough space to allocate the buf for the INS_JumpAnalysis\n"); 60 | // Consider removing this sprintf since it is very slow 61 | sprintf(buf, "\n%08x@%08x\0", ins_end, target_branch); 62 | 63 | if (isBuffered) 64 | recordTraceInMemory(buf, buf_len, trace) 65 | else 66 | recordTraceToFile(files[thread_idx], buf, buf_len, trace); 67 | 68 | /* Since this buf is either flushed or copied in memory we can free it */ 69 | free(buf); 70 | } 71 | 72 | void INS_WriteAnalysis(ADDRINT at, ADDRINT size) { 73 | if (upx_info->metJmp) return; 74 | time_t tv; 75 | START_STOPWATCH(tv); 76 | bool hasFoundRange = false; 77 | for each (pair interval in written_mem_intervals) { 78 | // Check if low address is in range 79 | if (IN_RANGE(at, interval.first, interval.second)) { 80 | // If high address is bigger than second interval enlarge it 81 | if ((at + size) > interval.second) interval.second = at + size; 82 | hasFoundRange = true; 83 | } 84 | 85 | // Check if high address is in range 86 | if (IN_RANGE(at + size, interval.first, interval.second)) { 87 | // If low address is smaller than first interval enlarge it 88 | if (at < interval.first) interval.first = at; 89 | hasFoundRange = true; 90 | } 91 | } 92 | 93 | // If no range has been found, let's create a new one 94 | if (!hasFoundRange) 95 | written_mem_intervals.push_front(make_pair(at, at + size)); 96 | total_writed_intervals_creation_time += GET_STOPWATCH_LAP(tv); 97 | } 98 | 99 | void INS_UPXEndAnalysis(OPCODE opcode) { 100 | if (!upx_info->metJmp) { 101 | if (opcode == XED_ICLASS_PUSHAD) 102 | upx_info->metPushad = true; 103 | else if (upx_info->metPushad && opcode == XED_ICLASS_POPAD) 104 | upx_info->metPopad = true; 105 | else if (upx_info->metPopad && opcode == XED_ICLASS_JMP) 106 | upx_info->metJmp = true; 107 | } 108 | } 109 | 110 | void INS_WXorX(ADDRINT at, const char* disasm_ins) { 111 | time_t tv; 112 | START_STOPWATCH(tv); 113 | for each (pair interval in written_mem_intervals) { 114 | if (IN_RANGE(at, interval.first, interval.second)) { 115 | if (upx_info->OEP == INVALID_ENTRY_POINT) 116 | upx_info->OEP = at; 117 | fprintf(upx_dump_file, "%s", disasm_ins); 118 | } 119 | } 120 | total_wxorx_check_time += GET_STOPWATCH_LAP(tv); 121 | } 122 | -------------------------------------------------------------------------------- /icount/callbacks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pin.H" 4 | 5 | void INS_EntryPoint(ADDRINT ip, THREADID thread_idx); 6 | void INS_Analysis(char* buf, UINT32 buf_len, THREADID thread_idx); 7 | void INS_JumpAnalysis(ADDRINT ins_end, ADDRINT target_branch, INT32 taken, THREADID thread_idx); 8 | void INS_WriteAnalysis(ADDRINT at, ADDRINT size); 9 | void INS_UPXEndAnalysis(OPCODE opcode); 10 | void INS_WXorX(ADDRINT at, const char* disasm_ins); -------------------------------------------------------------------------------- /icount/constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define Kb 1024 4 | #define Mb (1024*Kb) 5 | #define Gb (1024*Mb) 6 | 7 | #define CACHE_LINE_SIZE 64 8 | #define MAIN_THREAD_FAVOR_FACTOR 4 9 | 10 | #define INS_DELIMITER '\n' 11 | #define MAX_FILENAME_LENGTH 128 12 | 13 | #define THREAD_BUFFER_SIZE 30*Mb 14 | #define TRACE_LIMIT 2047*Mb 15 | #define TRACE_NAME_LENGTH_LIMIT 128 16 | #define THREADS_MAX_NO 256 17 | 18 | #define TEXT_SEC_NAME ".text" 19 | 20 | #define INVALID_ENTRY_POINT 0 -------------------------------------------------------------------------------- /icount/dump.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "pin.H" 4 | #include "main.h" 5 | #include "report.h" 6 | #include "loggers.h" 7 | 8 | void dumpImg(IMG img) { 9 | char dump_file_name[MAX_FILENAME_LENGTH] = { 0 }; 10 | sprintf(dump_file_name, "%s_img.dump", prog_name); 11 | FILE* dump_file = fopen(dump_file_name, "w+"); 12 | size_t img_size = main_img_memory.second - main_img_memory.first; 13 | char* dump = (char*) malloc(img_size); 14 | PIN_SafeCopy(dump, (void*) main_img_memory.first, img_size); 15 | fwrite(dump, sizeof(char), img_size, dump_file); 16 | fclose(dump_file); 17 | } 18 | 19 | void dumpSections(IMG img) { 20 | for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec)) { 21 | INFO("[*] Name: %s, from: 0x%08x to: 0x%08x\n", SEC_Name(sec).c_str(), SEC_Address(sec), SEC_Address(sec) + SEC_Size(sec)); 22 | FILE* f = fopen((SEC_Name(sec) + ".dump").c_str(), "w+"); 23 | char* sec_dump = (char*) malloc(SEC_Size(sec)); 24 | PIN_SafeCopy(sec_dump, (void*) SEC_Address(sec), SEC_Size(sec)); 25 | INFO("[+] Dumped %d/%d\n", fwrite(sec_dump, sizeof(char), SEC_Size(sec), f), SEC_Size(sec)); 26 | fclose(f); 27 | 28 | report_j["sections"][SEC_Name(sec)]["address"] = SEC_Address(sec); 29 | report_j["sections"][SEC_Name(sec)]["size"] = SEC_Size(sec); 30 | } 31 | } 32 | 33 | void dumpWrittenIntervals() { 34 | char dump_file_name[MAX_FILENAME_LENGTH] = { 0 }; 35 | sprintf(dump_file_name, "%s_written_intervals.dump", prog_name); 36 | FILE* dump_file = fopen(dump_file_name, "w+"); 37 | for each (pair interval in written_mem_intervals) { 38 | //INFO("[+] Dumping from 0x%08x to 0x%08x\n", interval.first, interval.second); 39 | char* dump = (char*) malloc(interval.second - interval.first); 40 | PIN_SafeCopy(dump, (void*) interval.first, interval.second - interval.first); 41 | fprintf(dump_file, "%s", dump); 42 | } 43 | fclose(dump_file); 44 | } -------------------------------------------------------------------------------- /icount/dump.h: -------------------------------------------------------------------------------- 1 | #include "pin.H" 2 | 3 | void dumpImg(IMG img); 4 | void dumpSections(IMG img); 5 | void dumpWrittenIntervals(); -------------------------------------------------------------------------------- /icount/error_handlers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "loggers.h" 3 | #include "pin.H" 4 | 5 | #define MALLOC_ERROR_HANDLER(buf, msg) {\ 6 | if (buf == NULL) {\ 7 | ERROR(msg);\ 8 | PIN_ExitProcess(1);\ 9 | }\ 10 | } 11 | 12 | #define ERROR_HANDLER(cond, msg) {\ 13 | if (cond) {\ 14 | ERROR(msg);\ 15 | PIN_ExitProcess(1);\ 16 | }\ 17 | } -------------------------------------------------------------------------------- /icount/flusher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "pin.H" 4 | #include "loggers.h" 5 | #include "constants.h" 6 | #include "utils.h" 7 | #include "flusher.h" 8 | #include "main.h" 9 | 10 | namespace flusher { 11 | PIN_SEMAPHORE flusher_ready_sem; 12 | PIN_SEMAPHORE flusher_sem; 13 | THREADID requesting_thread_idx = -1; 14 | doub_buf_trace_t* dbt; 15 | FILE* f; 16 | bool isPoisoned; 17 | 18 | void flusherThread(void* arg) { 19 | INFO("[*]{Flusher} Started with OS_THREADID %d\n", PIN_GetTid()); 20 | time_t tv, tx; 21 | while (1) { 22 | PIN_SemaphoreWait(&flusher_sem); 23 | START_STOPWATCH(tx); 24 | if (isPoisoned) return; 25 | INFO("[*]{Flusher} Received request from thread %d, flushing ...\n", requesting_thread_idx); 26 | dbt->isFlushing = true; 27 | 28 | START_STOPWATCH(tv); 29 | flushTraceToFile(f, dbt->flush_buf, dbt->flush_buf_len); 30 | total_flusher_flushing_time += GET_STOPWATCH_LAP(tv); 31 | 32 | free(dbt->flush_buf); 33 | dbt->isFlushing = false; 34 | dbt->isFlushBufEmpty = true; 35 | PIN_SemaphoreSet(&dbt->end_flush_sem); 36 | if (isPoisoned) return; 37 | PIN_SemaphoreClear(&flusher_sem); 38 | PIN_MutexUnlock(&flusher_req_mutex); 39 | total_flusher_time += GET_STOPWATCH_LAP(tx); 40 | INFO("[*]{Flusher} Completed request from thread %d, waiting for incoming requests ...\n", requesting_thread_idx); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /icount/flusher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "main.h" 3 | 4 | namespace flusher { 5 | void flusherThread(void* arg); 6 | 7 | extern THREADID requesting_thread_idx; 8 | extern doub_buf_trace_t* dbt; 9 | extern FILE* f; 10 | extern bool isPoisoned; 11 | 12 | extern PIN_SEMAPHORE flusher_sem; 13 | extern PIN_SEMAPHORE flusher_ready_sem; 14 | } -------------------------------------------------------------------------------- /icount/json.h: -------------------------------------------------------------------------------- 1 | /* DCD: to get it running under Pin CRT */ 2 | #define PIN_CRT 3 | #define JSON_USE_EXCEPTION 0 4 | 5 | /// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). 6 | /// It is intended to be used with #include "json/json.h" 7 | 8 | // ////////////////////////////////////////////////////////////////////// 9 | // Beginning of content of file: LICENSE 10 | // ////////////////////////////////////////////////////////////////////// 11 | 12 | /* 13 | The JsonCpp library's source code, including accompanying documentation, 14 | tests and demonstration applications, are licensed under the following 15 | conditions... 16 | 17 | The author (Baptiste Lepilleur) explicitly disclaims copyright in all 18 | jurisdictions which recognize such a disclaimer. In such jurisdictions, 19 | this software is released into the Public Domain. 20 | 21 | In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 22 | 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is 23 | released under the terms of the MIT License (see below). 24 | 25 | In jurisdictions which recognize Public Domain property, the user of this 26 | software may choose to accept it either as 1) Public Domain, 2) under the 27 | conditions of the MIT License (see below), or 3) under the terms of dual 28 | Public Domain/MIT License conditions described here, as they choose. 29 | 30 | The MIT License is about as close to Public Domain as a license can get, and is 31 | described in clear, concise terms at: 32 | 33 | http://en.wikipedia.org/wiki/MIT_License 34 | 35 | The full text of the MIT License follows: 36 | 37 | ======================================================================== 38 | Copyright (c) 2007-2010 Baptiste Lepilleur 39 | 40 | Permission is hereby granted, free of charge, to any person 41 | obtaining a copy of this software and associated documentation 42 | files (the "Software"), to deal in the Software without 43 | restriction, including without limitation the rights to use, copy, 44 | modify, merge, publish, distribute, sublicense, and/or sell copies 45 | of the Software, and to permit persons to whom the Software is 46 | furnished to do so, subject to the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be 49 | included in all copies or substantial portions of the Software. 50 | 51 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 52 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 53 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 54 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 55 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 56 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 57 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 58 | SOFTWARE. 59 | ======================================================================== 60 | (END LICENSE TEXT) 61 | 62 | The MIT license is compatible with both the GPL and commercial 63 | software, affording one all of the rights of Public Domain with the 64 | minor nuisance of being required to keep the above copyright notice 65 | and license text in the source code. Note also that by accepting the 66 | Public Domain "license" you can re-license your copy using whatever 67 | license you like. 68 | 69 | */ 70 | 71 | // ////////////////////////////////////////////////////////////////////// 72 | // End of content of file: LICENSE 73 | // ////////////////////////////////////////////////////////////////////// 74 | 75 | 76 | 77 | 78 | 79 | #ifndef JSON_AMALGATED_H_INCLUDED 80 | # define JSON_AMALGATED_H_INCLUDED 81 | /// If defined, indicates that the source file is amalgated 82 | /// to prevent private header inclusion. 83 | #define JSON_IS_AMALGAMATION 84 | 85 | // ////////////////////////////////////////////////////////////////////// 86 | // Beginning of content of file: include/json/version.h 87 | // ////////////////////////////////////////////////////////////////////// 88 | 89 | // DO NOT EDIT. This file (and "version") is generated by CMake. 90 | // Run CMake configure step to update it. 91 | #ifndef JSON_VERSION_H_INCLUDED 92 | # define JSON_VERSION_H_INCLUDED 93 | 94 | # define JSONCPP_VERSION_STRING "1.7.2" 95 | # define JSONCPP_VERSION_MAJOR 1 96 | # define JSONCPP_VERSION_MINOR 7 97 | # define JSONCPP_VERSION_PATCH 2 98 | # define JSONCPP_VERSION_QUALIFIER 99 | # define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) 100 | 101 | #ifdef JSONCPP_USING_SECURE_MEMORY 102 | #undef JSONCPP_USING_SECURE_MEMORY 103 | #endif 104 | #define JSONCPP_USING_SECURE_MEMORY 0 105 | // If non-zero, the library zeroes any memory that it has allocated before 106 | // it frees its memory. 107 | 108 | #endif // JSON_VERSION_H_INCLUDED 109 | 110 | // ////////////////////////////////////////////////////////////////////// 111 | // End of content of file: include/json/version.h 112 | // ////////////////////////////////////////////////////////////////////// 113 | 114 | 115 | 116 | 117 | 118 | 119 | // ////////////////////////////////////////////////////////////////////// 120 | // Beginning of content of file: include/json/config.h 121 | // ////////////////////////////////////////////////////////////////////// 122 | 123 | // Copyright 2007-2010 Baptiste Lepilleur 124 | // Distributed under MIT license, or public domain if desired and 125 | // recognized in your jurisdiction. 126 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 127 | 128 | #ifndef JSON_CONFIG_H_INCLUDED 129 | #define JSON_CONFIG_H_INCLUDED 130 | #include 131 | #include //typdef String 132 | 133 | /// If defined, indicates that json library is embedded in CppTL library. 134 | //# define JSON_IN_CPPTL 1 135 | 136 | /// If defined, indicates that json may leverage CppTL library 137 | //# define JSON_USE_CPPTL 1 138 | /// If defined, indicates that cpptl vector based map should be used instead of 139 | /// std::map 140 | /// as Value container. 141 | //# define JSON_USE_CPPTL_SMALLMAP 1 142 | 143 | // If non-zero, the library uses exceptions to report bad input instead of C 144 | // assertion macros. The default is to use exceptions. 145 | #ifndef JSON_USE_EXCEPTION 146 | #define JSON_USE_EXCEPTION 1 147 | #endif 148 | 149 | /// If defined, indicates that the source file is amalgated 150 | /// to prevent private header inclusion. 151 | /// Remarks: it is automatically defined in the generated amalgated header. 152 | // #define JSON_IS_AMALGAMATION 153 | 154 | #ifdef JSON_IN_CPPTL 155 | #include 156 | #ifndef JSON_USE_CPPTL 157 | #define JSON_USE_CPPTL 1 158 | #endif 159 | #endif 160 | 161 | #ifdef JSON_IN_CPPTL 162 | #define JSON_API CPPTL_API 163 | #elif defined(JSON_DLL_BUILD) 164 | #if defined(_MSC_VER) || defined(__MINGW32__) 165 | #define JSON_API __declspec(dllexport) 166 | #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING 167 | #endif // if defined(_MSC_VER) 168 | #elif defined(JSON_DLL) 169 | #if defined(_MSC_VER) || defined(__MINGW32__) 170 | #define JSON_API __declspec(dllimport) 171 | #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING 172 | #endif // if defined(_MSC_VER) 173 | #endif // ifdef JSON_IN_CPPTL 174 | #if !defined(JSON_API) 175 | #define JSON_API 176 | #endif 177 | 178 | // If JSON_NO_INT64 is defined, then Json only support C++ "int" type for 179 | // integer 180 | // Storages, and 64 bits integer support is disabled. 181 | // #define JSON_NO_INT64 1 182 | 183 | #if defined(_MSC_VER) // MSVC 184 | # if _MSC_VER <= 1200 // MSVC 6 185 | // Microsoft Visual Studio 6 only support conversion from __int64 to double 186 | // (no conversion from unsigned __int64). 187 | # define JSON_USE_INT64_DOUBLE_CONVERSION 1 188 | // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' 189 | // characters in the debug information) 190 | // All projects I've ever seen with VS6 were using this globally (not bothering 191 | // with pragma push/pop). 192 | # pragma warning(disable : 4786) 193 | # endif // MSVC 6 194 | 195 | # if _MSC_VER >= 1500 // MSVC 2008 196 | /// Indicates that the following function is deprecated. 197 | # define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) 198 | # endif 199 | 200 | #endif // defined(_MSC_VER) 201 | 202 | // In c++11 the override keyword allows you to explicity define that a function 203 | // is intended to override the base-class version. This makes the code more 204 | // managable and fixes a set of common hard-to-find bugs. 205 | #ifdef PIN_CRT 206 | #define JSONCPP_OVERRIDE 207 | #else 208 | #if __cplusplus >= 201103L 209 | # define JSONCPP_OVERRIDE override 210 | #elif defined(_MSC_VER) && _MSC_VER > 1600 211 | # define JSONCPP_OVERRIDE override 212 | #else 213 | # define JSONCPP_OVERRIDE 214 | #endif 215 | #endif 216 | 217 | #ifndef JSON_HAS_RVALUE_REFERENCES 218 | #ifndef PIN_CRT 219 | #if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 220 | #define JSON_HAS_RVALUE_REFERENCES 1 221 | #endif 222 | #endif // MSVC >= 2010 223 | 224 | #ifdef __clang__ 225 | #if __has_feature(cxx_rvalue_references) 226 | #define JSON_HAS_RVALUE_REFERENCES 1 227 | #endif // has_feature 228 | 229 | #elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) 230 | #if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) 231 | #define JSON_HAS_RVALUE_REFERENCES 1 232 | #endif // GXX_EXPERIMENTAL 233 | 234 | #endif // __clang__ || __GNUC__ 235 | 236 | #endif // not defined JSON_HAS_RVALUE_REFERENCES 237 | 238 | #ifndef JSON_HAS_RVALUE_REFERENCES 239 | #define JSON_HAS_RVALUE_REFERENCES 0 240 | #endif 241 | 242 | #ifdef __clang__ 243 | #elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) 244 | # if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) 245 | # define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) 246 | # elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) 247 | # define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) 248 | # endif // GNUC version 249 | #endif // __clang__ || __GNUC__ 250 | 251 | #if !defined(JSONCPP_DEPRECATED) 252 | #define JSONCPP_DEPRECATED(message) 253 | #endif // if !defined(JSONCPP_DEPRECATED) 254 | 255 | #if __GNUC__ >= 6 256 | # define JSON_USE_INT64_DOUBLE_CONVERSION 1 257 | #endif 258 | 259 | #if !defined(JSON_IS_AMALGAMATION) 260 | 261 | # include "version.h" 262 | 263 | # if JSONCPP_USING_SECURE_MEMORY 264 | # include "allocator.h" //typedef Allocator 265 | # endif 266 | 267 | #endif // if !defined(JSON_IS_AMALGAMATION) 268 | 269 | namespace Json { 270 | typedef int Int; 271 | typedef unsigned int UInt; 272 | #if defined(JSON_NO_INT64) 273 | typedef int LargestInt; 274 | typedef unsigned int LargestUInt; 275 | #undef JSON_HAS_INT64 276 | #else // if defined(JSON_NO_INT64) 277 | // For Microsoft Visual use specific types as long long is not supported 278 | #if defined(_MSC_VER) // Microsoft Visual Studio 279 | typedef __int64 Int64; 280 | typedef unsigned __int64 UInt64; 281 | #else // if defined(_MSC_VER) // Other platforms, use long long 282 | typedef long long int Int64; 283 | typedef unsigned long long int UInt64; 284 | #endif // if defined(_MSC_VER) 285 | typedef Int64 LargestInt; 286 | typedef UInt64 LargestUInt; 287 | #define JSON_HAS_INT64 288 | #endif // if defined(JSON_NO_INT64) 289 | #if JSONCPP_USING_SECURE_MEMORY 290 | #define JSONCPP_STRING std::basic_string, Json::SecureAllocator > 291 | #define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > 292 | #define JSONCPP_OSTREAM std::basic_ostream> 293 | #define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > 294 | #define JSONCPP_ISTREAM std::istream 295 | #else 296 | #define JSONCPP_STRING std::string 297 | #define JSONCPP_OSTRINGSTREAM std::ostringstream 298 | #define JSONCPP_OSTREAM std::ostream 299 | #define JSONCPP_ISTRINGSTREAM std::istringstream 300 | #define JSONCPP_ISTREAM std::istream 301 | #endif // if JSONCPP_USING_SECURE_MEMORY 302 | } // end namespace Json 303 | 304 | #endif // JSON_CONFIG_H_INCLUDED 305 | 306 | // ////////////////////////////////////////////////////////////////////// 307 | // End of content of file: include/json/config.h 308 | // ////////////////////////////////////////////////////////////////////// 309 | 310 | 311 | 312 | 313 | 314 | 315 | // ////////////////////////////////////////////////////////////////////// 316 | // Beginning of content of file: include/json/forwards.h 317 | // ////////////////////////////////////////////////////////////////////// 318 | 319 | // Copyright 2007-2010 Baptiste Lepilleur 320 | // Distributed under MIT license, or public domain if desired and 321 | // recognized in your jurisdiction. 322 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 323 | 324 | #ifndef JSON_FORWARDS_H_INCLUDED 325 | #define JSON_FORWARDS_H_INCLUDED 326 | 327 | #if !defined(JSON_IS_AMALGAMATION) 328 | #include "config.h" 329 | #endif // if !defined(JSON_IS_AMALGAMATION) 330 | 331 | namespace Json { 332 | 333 | // writer.h 334 | class FastWriter; 335 | class StyledWriter; 336 | 337 | // reader.h 338 | class Reader; 339 | 340 | // features.h 341 | class Features; 342 | 343 | // value.h 344 | typedef unsigned int ArrayIndex; 345 | class StaticString; 346 | class Path; 347 | class PathArgument; 348 | class Value; 349 | class ValueIteratorBase; 350 | class ValueIterator; 351 | class ValueConstIterator; 352 | 353 | } // namespace Json 354 | 355 | #endif // JSON_FORWARDS_H_INCLUDED 356 | 357 | // ////////////////////////////////////////////////////////////////////// 358 | // End of content of file: include/json/forwards.h 359 | // ////////////////////////////////////////////////////////////////////// 360 | 361 | 362 | 363 | 364 | 365 | 366 | // ////////////////////////////////////////////////////////////////////// 367 | // Beginning of content of file: include/json/features.h 368 | // ////////////////////////////////////////////////////////////////////// 369 | 370 | // Copyright 2007-2010 Baptiste Lepilleur 371 | // Distributed under MIT license, or public domain if desired and 372 | // recognized in your jurisdiction. 373 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 374 | 375 | #ifndef CPPTL_JSON_FEATURES_H_INCLUDED 376 | #define CPPTL_JSON_FEATURES_H_INCLUDED 377 | 378 | #if !defined(JSON_IS_AMALGAMATION) 379 | #include "forwards.h" 380 | #endif // if !defined(JSON_IS_AMALGAMATION) 381 | 382 | namespace Json { 383 | 384 | /** \brief Configuration passed to reader and writer. 385 | * This configuration object can be used to force the Reader or Writer 386 | * to behave in a standard conforming way. 387 | */ 388 | class JSON_API Features { 389 | public: 390 | /** \brief A configuration that allows all features and assumes all strings 391 | * are UTF-8. 392 | * - C & C++ comments are allowed 393 | * - Root object can be any JSON value 394 | * - Assumes Value strings are encoded in UTF-8 395 | */ 396 | static Features all(); 397 | 398 | /** \brief A configuration that is strictly compatible with the JSON 399 | * specification. 400 | * - Comments are forbidden. 401 | * - Root object must be either an array or an object value. 402 | * - Assumes Value strings are encoded in UTF-8 403 | */ 404 | static Features strictMode(); 405 | 406 | /** \brief Initialize the configuration like JsonConfig::allFeatures; 407 | */ 408 | Features(); 409 | 410 | /// \c true if comments are allowed. Default: \c true. 411 | bool allowComments_; 412 | 413 | /// \c true if root must be either an array or an object value. Default: \c 414 | /// false. 415 | bool strictRoot_; 416 | 417 | /// \c true if dropped null placeholders are allowed. Default: \c false. 418 | bool allowDroppedNullPlaceholders_; 419 | 420 | /// \c true if numeric object key are allowed. Default: \c false. 421 | bool allowNumericKeys_; 422 | }; 423 | 424 | } // namespace Json 425 | 426 | #endif // CPPTL_JSON_FEATURES_H_INCLUDED 427 | 428 | // ////////////////////////////////////////////////////////////////////// 429 | // End of content of file: include/json/features.h 430 | // ////////////////////////////////////////////////////////////////////// 431 | 432 | 433 | 434 | 435 | 436 | 437 | // ////////////////////////////////////////////////////////////////////// 438 | // Beginning of content of file: include/json/value.h 439 | // ////////////////////////////////////////////////////////////////////// 440 | 441 | // Copyright 2007-2010 Baptiste Lepilleur 442 | // Distributed under MIT license, or public domain if desired and 443 | // recognized in your jurisdiction. 444 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 445 | 446 | #ifndef CPPTL_JSON_H_INCLUDED 447 | #define CPPTL_JSON_H_INCLUDED 448 | 449 | #if !defined(JSON_IS_AMALGAMATION) 450 | #include "forwards.h" 451 | #endif // if !defined(JSON_IS_AMALGAMATION) 452 | #include 453 | #include 454 | #include 455 | 456 | #ifndef JSON_USE_CPPTL_SMALLMAP 457 | #include 458 | #else 459 | #include 460 | #endif 461 | #ifdef JSON_USE_CPPTL 462 | #include 463 | #endif 464 | 465 | //Conditional NORETURN attribute on the throw functions would: 466 | // a) suppress false positives from static code analysis 467 | // b) possibly improve optimization opportunities. 468 | #if !defined(JSONCPP_NORETURN) 469 | # if defined(_MSC_VER) 470 | # define JSONCPP_NORETURN __declspec(noreturn) 471 | # elif defined(__GNUC__) 472 | # define JSONCPP_NORETURN __attribute__ ((__noreturn__)) 473 | # else 474 | # define JSONCPP_NORETURN 475 | # endif 476 | #endif 477 | 478 | // Disable warning C4251: : needs to have dll-interface to 479 | // be used by... 480 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 481 | #pragma warning(push) 482 | #pragma warning(disable : 4251) 483 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 484 | 485 | /** \brief JSON (JavaScript Object Notation). 486 | */ 487 | namespace Json { 488 | 489 | /** Base class for all exceptions we throw. 490 | * 491 | * We use nothing but these internally. Of course, STL can throw others. 492 | */ 493 | class JSON_API Exception : public std::exception { 494 | public: 495 | Exception(JSONCPP_STRING const& msg); 496 | ~Exception() throw() JSONCPP_OVERRIDE; 497 | char const* what() const throw() JSONCPP_OVERRIDE; 498 | protected: 499 | JSONCPP_STRING msg_; 500 | }; 501 | 502 | /** Exceptions which the user cannot easily avoid. 503 | * 504 | * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input 505 | * 506 | * \remark derived from Json::Exception 507 | */ 508 | class JSON_API RuntimeError : public Exception { 509 | public: 510 | RuntimeError(JSONCPP_STRING const& msg); 511 | }; 512 | 513 | /** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. 514 | * 515 | * These are precondition-violations (user bugs) and internal errors (our bugs). 516 | * 517 | * \remark derived from Json::Exception 518 | */ 519 | class JSON_API LogicError : public Exception { 520 | public: 521 | LogicError(JSONCPP_STRING const& msg); 522 | }; 523 | 524 | /// used internally 525 | JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); 526 | /// used internally 527 | JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); 528 | 529 | /** \brief Type of the value held by a Value object. 530 | */ 531 | enum ValueType { 532 | nullValue = 0, ///< 'null' value 533 | intValue, ///< signed integer value 534 | uintValue, ///< unsigned integer value 535 | realValue, ///< double value 536 | stringValue, ///< UTF-8 string value 537 | booleanValue, ///< bool value 538 | arrayValue, ///< array value (ordered list) 539 | objectValue ///< object value (collection of name/value pairs). 540 | }; 541 | 542 | enum CommentPlacement { 543 | commentBefore = 0, ///< a comment placed on the line before a value 544 | commentAfterOnSameLine, ///< a comment just after a value on the same line 545 | commentAfter, ///< a comment on the line after a value (only make sense for 546 | /// root value) 547 | numberOfCommentPlacement 548 | }; 549 | 550 | //# ifdef JSON_USE_CPPTL 551 | // typedef CppTL::AnyEnumerator EnumMemberNames; 552 | // typedef CppTL::AnyEnumerator EnumValues; 553 | //# endif 554 | 555 | /** \brief Lightweight wrapper to tag static string. 556 | * 557 | * Value constructor and objectValue member assignement takes advantage of the 558 | * StaticString and avoid the cost of string duplication when storing the 559 | * string or the member name. 560 | * 561 | * Example of usage: 562 | * \code 563 | * Json::Value aValue( StaticString("some text") ); 564 | * Json::Value object; 565 | * static const StaticString code("code"); 566 | * object[code] = 1234; 567 | * \endcode 568 | */ 569 | class JSON_API StaticString { 570 | public: 571 | explicit StaticString(const char* czstring) : c_str_(czstring) {} 572 | 573 | operator const char*() const { return c_str_; } 574 | 575 | const char* c_str() const { return c_str_; } 576 | 577 | private: 578 | const char* c_str_; 579 | }; 580 | 581 | /** \brief Represents a JSON value. 582 | * 583 | * This class is a discriminated union wrapper that can represents a: 584 | * - signed integer [range: Value::minInt - Value::maxInt] 585 | * - unsigned integer (range: 0 - Value::maxUInt) 586 | * - double 587 | * - UTF-8 string 588 | * - boolean 589 | * - 'null' 590 | * - an ordered list of Value 591 | * - collection of name/value pairs (javascript object) 592 | * 593 | * The type of the held value is represented by a #ValueType and 594 | * can be obtained using type(). 595 | * 596 | * Values of an #objectValue or #arrayValue can be accessed using operator[]() 597 | * methods. 598 | * Non-const methods will automatically create the a #nullValue element 599 | * if it does not exist. 600 | * The sequence of an #arrayValue will be automatically resized and initialized 601 | * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. 602 | * 603 | * The get() methods can be used to obtain default value in the case the 604 | * required element does not exist. 605 | * 606 | * It is possible to iterate over the list of a #objectValue values using 607 | * the getMemberNames() method. 608 | * 609 | * \note #Value string-length fit in size_t, but keys must be < 2^30. 610 | * (The reason is an implementation detail.) A #CharReader will raise an 611 | * exception if a bound is exceeded to avoid security holes in your app, 612 | * but the Value API does *not* check bounds. That is the responsibility 613 | * of the caller. 614 | */ 615 | class JSON_API Value { 616 | friend class ValueIteratorBase; 617 | public: 618 | typedef std::vector Members; 619 | typedef ValueIterator iterator; 620 | typedef ValueConstIterator const_iterator; 621 | typedef Json::UInt UInt; 622 | typedef Json::Int Int; 623 | #if defined(JSON_HAS_INT64) 624 | typedef Json::UInt64 UInt64; 625 | typedef Json::Int64 Int64; 626 | #endif // defined(JSON_HAS_INT64) 627 | typedef Json::LargestInt LargestInt; 628 | typedef Json::LargestUInt LargestUInt; 629 | typedef Json::ArrayIndex ArrayIndex; 630 | 631 | static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). 632 | static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null 633 | /// Minimum signed integer value that can be stored in a Json::Value. 634 | static const LargestInt minLargestInt; 635 | /// Maximum signed integer value that can be stored in a Json::Value. 636 | static const LargestInt maxLargestInt; 637 | /// Maximum unsigned integer value that can be stored in a Json::Value. 638 | static const LargestUInt maxLargestUInt; 639 | 640 | /// Minimum signed int value that can be stored in a Json::Value. 641 | static const Int minInt; 642 | /// Maximum signed int value that can be stored in a Json::Value. 643 | static const Int maxInt; 644 | /// Maximum unsigned int value that can be stored in a Json::Value. 645 | static const UInt maxUInt; 646 | 647 | #if defined(JSON_HAS_INT64) 648 | /// Minimum signed 64 bits int value that can be stored in a Json::Value. 649 | static const Int64 minInt64; 650 | /// Maximum signed 64 bits int value that can be stored in a Json::Value. 651 | static const Int64 maxInt64; 652 | /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. 653 | static const UInt64 maxUInt64; 654 | #endif // defined(JSON_HAS_INT64) 655 | 656 | private: 657 | #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 658 | class CZString { 659 | public: 660 | enum DuplicationPolicy { 661 | noDuplication = 0, 662 | duplicate, 663 | duplicateOnCopy 664 | }; 665 | CZString(ArrayIndex index); 666 | CZString(char const* str, unsigned length, DuplicationPolicy allocate); 667 | CZString(CZString const& other); 668 | #if JSON_HAS_RVALUE_REFERENCES 669 | CZString(CZString&& other); 670 | #endif 671 | ~CZString(); 672 | CZString& operator=(CZString other); 673 | bool operator<(CZString const& other) const; 674 | bool operator==(CZString const& other) const; 675 | ArrayIndex index() const; 676 | //const char* c_str() const; ///< \deprecated 677 | char const* data() const; 678 | unsigned length() const; 679 | bool isStaticString() const; 680 | 681 | private: 682 | void swap(CZString& other); 683 | 684 | struct StringStorage { 685 | unsigned policy_ : 2; 686 | unsigned length_ : 30; // 1GB max 687 | }; 688 | 689 | char const* cstr_; // actually, a prefixed string, unless policy is noDup 690 | union { 691 | ArrayIndex index_; 692 | StringStorage storage_; 693 | }; 694 | }; 695 | 696 | public: 697 | #ifndef JSON_USE_CPPTL_SMALLMAP 698 | typedef std::map ObjectValues; 699 | #else 700 | typedef CppTL::SmallMap ObjectValues; 701 | #endif // ifndef JSON_USE_CPPTL_SMALLMAP 702 | #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 703 | 704 | public: 705 | /** \brief Create a default Value of the given type. 706 | 707 | This is a very useful constructor. 708 | To create an empty array, pass arrayValue. 709 | To create an empty object, pass objectValue. 710 | Another Value can then be set to this one by assignment. 711 | This is useful since clear() and resize() will not alter types. 712 | 713 | Examples: 714 | \code 715 | Json::Value null_value; // null 716 | Json::Value arr_value(Json::arrayValue); // [] 717 | Json::Value obj_value(Json::objectValue); // {} 718 | \endcode 719 | */ 720 | Value(ValueType type = nullValue); 721 | Value(Int value); 722 | Value(UInt value); 723 | #if defined(JSON_HAS_INT64) 724 | Value(Int64 value); 725 | Value(UInt64 value); 726 | #endif // if defined(JSON_HAS_INT64) 727 | Value(double value); 728 | Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) 729 | Value(const char* begin, const char* end); ///< Copy all, incl zeroes. 730 | /** \brief Constructs a value from a static string. 731 | 732 | * Like other value string constructor but do not duplicate the string for 733 | * internal storage. The given string must remain alive after the call to this 734 | * constructor. 735 | * \note This works only for null-terminated strings. (We cannot change the 736 | * size of this class, so we have nowhere to store the length, 737 | * which might be computed later for various operations.) 738 | * 739 | * Example of usage: 740 | * \code 741 | * static StaticString foo("some text"); 742 | * Json::Value aValue(foo); 743 | * \endcode 744 | */ 745 | Value(const StaticString& value); 746 | Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. 747 | #ifdef JSON_USE_CPPTL 748 | Value(const CppTL::ConstString& value); 749 | #endif 750 | Value(bool value); 751 | /// Deep copy. 752 | Value(const Value& other); 753 | #if JSON_HAS_RVALUE_REFERENCES 754 | /// Move constructor 755 | Value(Value&& other); 756 | #endif 757 | ~Value(); 758 | 759 | /// Deep copy, then swap(other). 760 | /// \note Over-write existing comments. To preserve comments, use #swapPayload(). 761 | Value& operator=(Value other); 762 | /// Swap everything. 763 | void swap(Value& other); 764 | /// Swap values but leave comments and source offsets in place. 765 | void swapPayload(Value& other); 766 | 767 | ValueType type() const; 768 | 769 | /// Compare payload only, not comments etc. 770 | bool operator<(const Value& other) const; 771 | bool operator<=(const Value& other) const; 772 | bool operator>=(const Value& other) const; 773 | bool operator>(const Value& other) const; 774 | bool operator==(const Value& other) const; 775 | bool operator!=(const Value& other) const; 776 | int compare(const Value& other) const; 777 | 778 | const char* asCString() const; ///< Embedded zeroes could cause you trouble! 779 | #if JSONCPP_USING_SECURE_MEMORY 780 | unsigned getCStringLength() const; //Allows you to understand the length of the CString 781 | #endif 782 | JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. 783 | /** Get raw char* of string-value. 784 | * \return false if !string. (Seg-fault if str or end are NULL.) 785 | */ 786 | bool getString( 787 | char const** begin, char const** end) const; 788 | #ifdef JSON_USE_CPPTL 789 | CppTL::ConstString asConstString() const; 790 | #endif 791 | Int asInt() const; 792 | UInt asUInt() const; 793 | #if defined(JSON_HAS_INT64) 794 | Int64 asInt64() const; 795 | UInt64 asUInt64() const; 796 | #endif // if defined(JSON_HAS_INT64) 797 | LargestInt asLargestInt() const; 798 | LargestUInt asLargestUInt() const; 799 | float asFloat() const; 800 | double asDouble() const; 801 | bool asBool() const; 802 | 803 | bool isNull() const; 804 | bool isBool() const; 805 | bool isInt() const; 806 | bool isInt64() const; 807 | bool isUInt() const; 808 | bool isUInt64() const; 809 | bool isIntegral() const; 810 | bool isDouble() const; 811 | bool isNumeric() const; 812 | bool isString() const; 813 | bool isArray() const; 814 | bool isObject() const; 815 | 816 | bool isConvertibleTo(ValueType other) const; 817 | 818 | /// Number of values in array or object 819 | ArrayIndex size() const; 820 | 821 | /// \brief Return true if empty array, empty object, or null; 822 | /// otherwise, false. 823 | bool empty() const; 824 | 825 | /// Return isNull() 826 | bool operator!() const; 827 | 828 | /// Remove all object members and array elements. 829 | /// \pre type() is arrayValue, objectValue, or nullValue 830 | /// \post type() is unchanged 831 | void clear(); 832 | 833 | /// Resize the array to size elements. 834 | /// New elements are initialized to null. 835 | /// May only be called on nullValue or arrayValue. 836 | /// \pre type() is arrayValue or nullValue 837 | /// \post type() is arrayValue 838 | void resize(ArrayIndex size); 839 | 840 | /// Access an array element (zero based index ). 841 | /// If the array contains less than index element, then null value are 842 | /// inserted 843 | /// in the array so that its size is index+1. 844 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 845 | /// this from the operator[] which takes a string.) 846 | Value& operator[](ArrayIndex index); 847 | 848 | /// Access an array element (zero based index ). 849 | /// If the array contains less than index element, then null value are 850 | /// inserted 851 | /// in the array so that its size is index+1. 852 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 853 | /// this from the operator[] which takes a string.) 854 | Value& operator[](int index); 855 | 856 | /// Access an array element (zero based index ) 857 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 858 | /// this from the operator[] which takes a string.) 859 | const Value& operator[](ArrayIndex index) const; 860 | 861 | /// Access an array element (zero based index ) 862 | /// (You may need to say 'value[0u]' to get your compiler to distinguish 863 | /// this from the operator[] which takes a string.) 864 | const Value& operator[](int index) const; 865 | 866 | /// If the array contains at least index+1 elements, returns the element 867 | /// value, 868 | /// otherwise returns defaultValue. 869 | Value get(ArrayIndex index, const Value& defaultValue) const; 870 | /// Return true if index < size(). 871 | bool isValidIndex(ArrayIndex index) const; 872 | /// \brief Append value to array at the end. 873 | /// 874 | /// Equivalent to jsonvalue[jsonvalue.size()] = value; 875 | Value& append(const Value& value); 876 | 877 | /// Access an object value by name, create a null member if it does not exist. 878 | /// \note Because of our implementation, keys are limited to 2^30 -1 chars. 879 | /// Exceeding that will cause an exception. 880 | Value& operator[](const char* key); 881 | /// Access an object value by name, returns null if there is no member with 882 | /// that name. 883 | const Value& operator[](const char* key) const; 884 | /// Access an object value by name, create a null member if it does not exist. 885 | /// \param key may contain embedded nulls. 886 | Value& operator[](const JSONCPP_STRING& key); 887 | /// Access an object value by name, returns null if there is no member with 888 | /// that name. 889 | /// \param key may contain embedded nulls. 890 | const Value& operator[](const JSONCPP_STRING& key) const; 891 | /** \brief Access an object value by name, create a null member if it does not 892 | exist. 893 | 894 | * If the object has no entry for that name, then the member name used to store 895 | * the new entry is not duplicated. 896 | * Example of use: 897 | * \code 898 | * Json::Value object; 899 | * static const StaticString code("code"); 900 | * object[code] = 1234; 901 | * \endcode 902 | */ 903 | Value& operator[](const StaticString& key); 904 | #ifdef JSON_USE_CPPTL 905 | /// Access an object value by name, create a null member if it does not exist. 906 | Value& operator[](const CppTL::ConstString& key); 907 | /// Access an object value by name, returns null if there is no member with 908 | /// that name. 909 | const Value& operator[](const CppTL::ConstString& key) const; 910 | #endif 911 | /// Return the member named key if it exist, defaultValue otherwise. 912 | /// \note deep copy 913 | Value get(const char* key, const Value& defaultValue) const; 914 | /// Return the member named key if it exist, defaultValue otherwise. 915 | /// \note deep copy 916 | /// \note key may contain embedded nulls. 917 | Value get(const char* begin, const char* end, const Value& defaultValue) const; 918 | /// Return the member named key if it exist, defaultValue otherwise. 919 | /// \note deep copy 920 | /// \param key may contain embedded nulls. 921 | Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; 922 | #ifdef JSON_USE_CPPTL 923 | /// Return the member named key if it exist, defaultValue otherwise. 924 | /// \note deep copy 925 | Value get(const CppTL::ConstString& key, const Value& defaultValue) const; 926 | #endif 927 | /// Most general and efficient version of isMember()const, get()const, 928 | /// and operator[]const 929 | /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 930 | Value const* find(char const* begin, char const* end) const; 931 | /// Most general and efficient version of object-mutators. 932 | /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 933 | /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. 934 | Value const* demand(char const* begin, char const* end); 935 | /// \brief Remove and return the named member. 936 | /// 937 | /// Do nothing if it did not exist. 938 | /// \return the removed Value, or null. 939 | /// \pre type() is objectValue or nullValue 940 | /// \post type() is unchanged 941 | /// \deprecated 942 | Value removeMember(const char* key); 943 | /// Same as removeMember(const char*) 944 | /// \param key may contain embedded nulls. 945 | /// \deprecated 946 | Value removeMember(const JSONCPP_STRING& key); 947 | /// Same as removeMember(const char* begin, const char* end, Value* removed), 948 | /// but 'key' is null-terminated. 949 | bool removeMember(const char* key, Value* removed); 950 | /** \brief Remove the named map member. 951 | 952 | Update 'removed' iff removed. 953 | \param key may contain embedded nulls. 954 | \return true iff removed (no exceptions) 955 | */ 956 | bool removeMember(JSONCPP_STRING const& key, Value* removed); 957 | /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) 958 | bool removeMember(const char* begin, const char* end, Value* removed); 959 | /** \brief Remove the indexed array element. 960 | 961 | O(n) expensive operations. 962 | Update 'removed' iff removed. 963 | \return true iff removed (no exceptions) 964 | */ 965 | bool removeIndex(ArrayIndex i, Value* removed); 966 | 967 | /// Return true if the object has a member named key. 968 | /// \note 'key' must be null-terminated. 969 | bool isMember(const char* key) const; 970 | /// Return true if the object has a member named key. 971 | /// \param key may contain embedded nulls. 972 | bool isMember(const JSONCPP_STRING& key) const; 973 | /// Same as isMember(JSONCPP_STRING const& key)const 974 | bool isMember(const char* begin, const char* end) const; 975 | #ifdef JSON_USE_CPPTL 976 | /// Return true if the object has a member named key. 977 | bool isMember(const CppTL::ConstString& key) const; 978 | #endif 979 | 980 | /// \brief Return a list of the member names. 981 | /// 982 | /// If null, return an empty list. 983 | /// \pre type() is objectValue or nullValue 984 | /// \post if type() was nullValue, it remains nullValue 985 | Members getMemberNames() const; 986 | 987 | //# ifdef JSON_USE_CPPTL 988 | // EnumMemberNames enumMemberNames() const; 989 | // EnumValues enumValues() const; 990 | //# endif 991 | 992 | /// \deprecated Always pass len. 993 | JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") 994 | void setComment(const char* comment, CommentPlacement placement); 995 | /// Comments must be //... or /* ... */ 996 | void setComment(const char* comment, size_t len, CommentPlacement placement); 997 | /// Comments must be //... or /* ... */ 998 | void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); 999 | bool hasComment(CommentPlacement placement) const; 1000 | /// Include delimiters and embedded newlines. 1001 | JSONCPP_STRING getComment(CommentPlacement placement) const; 1002 | 1003 | JSONCPP_STRING toStyledString() const; 1004 | 1005 | const_iterator begin() const; 1006 | const_iterator end() const; 1007 | 1008 | iterator begin(); 1009 | iterator end(); 1010 | 1011 | // Accessors for the [start, limit) range of bytes within the JSON text from 1012 | // which this value was parsed, if any. 1013 | void setOffsetStart(ptrdiff_t start); 1014 | void setOffsetLimit(ptrdiff_t limit); 1015 | ptrdiff_t getOffsetStart() const; 1016 | ptrdiff_t getOffsetLimit() const; 1017 | 1018 | private: 1019 | void initBasic(ValueType type, bool allocated = false); 1020 | 1021 | Value& resolveReference(const char* key); 1022 | Value& resolveReference(const char* key, const char* end); 1023 | 1024 | struct CommentInfo { 1025 | CommentInfo(); 1026 | ~CommentInfo(); 1027 | 1028 | void setComment(const char* text, size_t len); 1029 | 1030 | char* comment_; 1031 | }; 1032 | 1033 | // struct MemberNamesTransform 1034 | //{ 1035 | // typedef const char *result_type; 1036 | // const char *operator()( const CZString &name ) const 1037 | // { 1038 | // return name.c_str(); 1039 | // } 1040 | //}; 1041 | 1042 | union ValueHolder { 1043 | LargestInt int_; 1044 | LargestUInt uint_; 1045 | double real_; 1046 | bool bool_; 1047 | char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ 1048 | ObjectValues* map_; 1049 | } value_; 1050 | ValueType type_ : 8; 1051 | unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. 1052 | // If not allocated_, string_ must be null-terminated. 1053 | CommentInfo* comments_; 1054 | 1055 | // [start, limit) byte offsets in the source JSON text from which this Value 1056 | // was extracted. 1057 | ptrdiff_t start_; 1058 | ptrdiff_t limit_; 1059 | }; 1060 | 1061 | /** \brief Experimental and untested: represents an element of the "path" to 1062 | * access a node. 1063 | */ 1064 | class JSON_API PathArgument { 1065 | public: 1066 | friend class Path; 1067 | 1068 | PathArgument(); 1069 | PathArgument(ArrayIndex index); 1070 | PathArgument(const char* key); 1071 | PathArgument(const JSONCPP_STRING& key); 1072 | 1073 | private: 1074 | enum Kind { 1075 | kindNone = 0, 1076 | kindIndex, 1077 | kindKey 1078 | }; 1079 | JSONCPP_STRING key_; 1080 | ArrayIndex index_; 1081 | Kind kind_; 1082 | }; 1083 | 1084 | /** \brief Experimental and untested: represents a "path" to access a node. 1085 | * 1086 | * Syntax: 1087 | * - "." => root node 1088 | * - ".[n]" => elements at index 'n' of root node (an array value) 1089 | * - ".name" => member named 'name' of root node (an object value) 1090 | * - ".name1.name2.name3" 1091 | * - ".[0][1][2].name1[3]" 1092 | * - ".%" => member name is provided as parameter 1093 | * - ".[%]" => index is provied as parameter 1094 | */ 1095 | class JSON_API Path { 1096 | public: 1097 | Path(const JSONCPP_STRING& path, 1098 | const PathArgument& a1 = PathArgument(), 1099 | const PathArgument& a2 = PathArgument(), 1100 | const PathArgument& a3 = PathArgument(), 1101 | const PathArgument& a4 = PathArgument(), 1102 | const PathArgument& a5 = PathArgument()); 1103 | 1104 | const Value& resolve(const Value& root) const; 1105 | Value resolve(const Value& root, const Value& defaultValue) const; 1106 | /// Creates the "path" to access the specified node and returns a reference on 1107 | /// the node. 1108 | Value& make(Value& root) const; 1109 | 1110 | private: 1111 | typedef std::vector InArgs; 1112 | typedef std::vector Args; 1113 | 1114 | void makePath(const JSONCPP_STRING& path, const InArgs& in); 1115 | void addPathInArg(const JSONCPP_STRING& path, 1116 | const InArgs& in, 1117 | InArgs::const_iterator& itInArg, 1118 | PathArgument::Kind kind); 1119 | void invalidPath(const JSONCPP_STRING& path, int location); 1120 | 1121 | Args args_; 1122 | }; 1123 | 1124 | /** \brief base class for Value iterators. 1125 | * 1126 | */ 1127 | class JSON_API ValueIteratorBase { 1128 | public: 1129 | typedef std::bidirectional_iterator_tag iterator_category; 1130 | typedef unsigned int size_t; 1131 | typedef int difference_type; 1132 | typedef ValueIteratorBase SelfType; 1133 | 1134 | bool operator==(const SelfType& other) const { return isEqual(other); } 1135 | 1136 | bool operator!=(const SelfType& other) const { return !isEqual(other); } 1137 | 1138 | difference_type operator-(const SelfType& other) const { 1139 | return other.computeDistance(*this); 1140 | } 1141 | 1142 | /// Return either the index or the member name of the referenced value as a 1143 | /// Value. 1144 | Value key() const; 1145 | 1146 | /// Return the index of the referenced Value, or -1 if it is not an arrayValue. 1147 | UInt index() const; 1148 | 1149 | /// Return the member name of the referenced Value, or "" if it is not an 1150 | /// objectValue. 1151 | /// \note Avoid `c_str()` on result, as embedded zeroes are possible. 1152 | JSONCPP_STRING name() const; 1153 | 1154 | /// Return the member name of the referenced Value. "" if it is not an 1155 | /// objectValue. 1156 | /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. 1157 | JSONCPP_DEPRECATED("Use `key = name();` instead.") 1158 | char const* memberName() const; 1159 | /// Return the member name of the referenced Value, or NULL if it is not an 1160 | /// objectValue. 1161 | /// \note Better version than memberName(). Allows embedded nulls. 1162 | char const* memberName(char const** end) const; 1163 | 1164 | protected: 1165 | Value& deref() const; 1166 | 1167 | void increment(); 1168 | 1169 | void decrement(); 1170 | 1171 | difference_type computeDistance(const SelfType& other) const; 1172 | 1173 | bool isEqual(const SelfType& other) const; 1174 | 1175 | void copy(const SelfType& other); 1176 | 1177 | private: 1178 | Value::ObjectValues::iterator current_; 1179 | // Indicates that iterator is for a null value. 1180 | bool isNull_; 1181 | 1182 | public: 1183 | // For some reason, BORLAND needs these at the end, rather 1184 | // than earlier. No idea why. 1185 | ValueIteratorBase(); 1186 | explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); 1187 | }; 1188 | 1189 | /** \brief const iterator for object and array value. 1190 | * 1191 | */ 1192 | class JSON_API ValueConstIterator : public ValueIteratorBase { 1193 | friend class Value; 1194 | 1195 | public: 1196 | typedef const Value value_type; 1197 | //typedef unsigned int size_t; 1198 | //typedef int difference_type; 1199 | typedef const Value& reference; 1200 | typedef const Value* pointer; 1201 | typedef ValueConstIterator SelfType; 1202 | 1203 | ValueConstIterator(); 1204 | ValueConstIterator(ValueIterator const& other); 1205 | 1206 | private: 1207 | /*! \internal Use by Value to create an iterator. 1208 | */ 1209 | explicit ValueConstIterator(const Value::ObjectValues::iterator& current); 1210 | public: 1211 | SelfType& operator=(const ValueIteratorBase& other); 1212 | 1213 | SelfType operator++(int) { 1214 | SelfType temp(*this); 1215 | ++*this; 1216 | return temp; 1217 | } 1218 | 1219 | SelfType operator--(int) { 1220 | SelfType temp(*this); 1221 | --*this; 1222 | return temp; 1223 | } 1224 | 1225 | SelfType& operator--() { 1226 | decrement(); 1227 | return *this; 1228 | } 1229 | 1230 | SelfType& operator++() { 1231 | increment(); 1232 | return *this; 1233 | } 1234 | 1235 | reference operator*() const { return deref(); } 1236 | 1237 | pointer operator->() const { return &deref(); } 1238 | }; 1239 | 1240 | /** \brief Iterator for object and array value. 1241 | */ 1242 | class JSON_API ValueIterator : public ValueIteratorBase { 1243 | friend class Value; 1244 | 1245 | public: 1246 | typedef Value value_type; 1247 | typedef unsigned int size_t; 1248 | typedef int difference_type; 1249 | typedef Value& reference; 1250 | typedef Value* pointer; 1251 | typedef ValueIterator SelfType; 1252 | 1253 | ValueIterator(); 1254 | explicit ValueIterator(const ValueConstIterator& other); 1255 | ValueIterator(const ValueIterator& other); 1256 | 1257 | private: 1258 | /*! \internal Use by Value to create an iterator. 1259 | */ 1260 | explicit ValueIterator(const Value::ObjectValues::iterator& current); 1261 | public: 1262 | SelfType& operator=(const SelfType& other); 1263 | 1264 | SelfType operator++(int) { 1265 | SelfType temp(*this); 1266 | ++*this; 1267 | return temp; 1268 | } 1269 | 1270 | SelfType operator--(int) { 1271 | SelfType temp(*this); 1272 | --*this; 1273 | return temp; 1274 | } 1275 | 1276 | SelfType& operator--() { 1277 | decrement(); 1278 | return *this; 1279 | } 1280 | 1281 | SelfType& operator++() { 1282 | increment(); 1283 | return *this; 1284 | } 1285 | 1286 | reference operator*() const { return deref(); } 1287 | 1288 | pointer operator->() const { return &deref(); } 1289 | }; 1290 | 1291 | } // namespace Json 1292 | 1293 | 1294 | namespace std { 1295 | /// Specialize std::swap() for Json::Value. 1296 | template<> 1297 | inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } 1298 | } 1299 | 1300 | 1301 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1302 | #pragma warning(pop) 1303 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1304 | 1305 | #endif // CPPTL_JSON_H_INCLUDED 1306 | 1307 | // ////////////////////////////////////////////////////////////////////// 1308 | // End of content of file: include/json/value.h 1309 | // ////////////////////////////////////////////////////////////////////// 1310 | 1311 | 1312 | 1313 | 1314 | 1315 | 1316 | // ////////////////////////////////////////////////////////////////////// 1317 | // Beginning of content of file: include/json/reader.h 1318 | // ////////////////////////////////////////////////////////////////////// 1319 | 1320 | // Copyright 2007-2010 Baptiste Lepilleur 1321 | // Distributed under MIT license, or public domain if desired and 1322 | // recognized in your jurisdiction. 1323 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 1324 | 1325 | #ifndef CPPTL_JSON_READER_H_INCLUDED 1326 | #define CPPTL_JSON_READER_H_INCLUDED 1327 | 1328 | #if !defined(JSON_IS_AMALGAMATION) 1329 | #include "features.h" 1330 | #include "value.h" 1331 | #endif // if !defined(JSON_IS_AMALGAMATION) 1332 | #include 1333 | #include 1334 | #include 1335 | #include 1336 | #include 1337 | 1338 | // Disable warning C4251: : needs to have dll-interface to 1339 | // be used by... 1340 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1341 | #pragma warning(push) 1342 | #pragma warning(disable : 4251) 1343 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1344 | 1345 | namespace Json { 1346 | 1347 | /** \brief Unserialize a JSON document into a 1348 | *Value. 1349 | * 1350 | * \deprecated Use CharReader and CharReaderBuilder. 1351 | */ 1352 | class JSON_API Reader { 1353 | public: 1354 | typedef char Char; 1355 | typedef const Char* Location; 1356 | 1357 | /** \brief An error tagged with where in the JSON text it was encountered. 1358 | * 1359 | * The offsets give the [start, limit) range of bytes within the text. Note 1360 | * that this is bytes, not codepoints. 1361 | * 1362 | */ 1363 | struct StructuredError { 1364 | ptrdiff_t offset_start; 1365 | ptrdiff_t offset_limit; 1366 | JSONCPP_STRING message; 1367 | }; 1368 | 1369 | /** \brief Constructs a Reader allowing all features 1370 | * for parsing. 1371 | */ 1372 | Reader(); 1373 | 1374 | /** \brief Constructs a Reader allowing the specified feature set 1375 | * for parsing. 1376 | */ 1377 | Reader(const Features& features); 1378 | 1379 | /** \brief Read a Value from a JSON 1380 | * document. 1381 | * \param document UTF-8 encoded string containing the document to read. 1382 | * \param root [out] Contains the root value of the document if it was 1383 | * successfully parsed. 1384 | * \param collectComments \c true to collect comment and allow writing them 1385 | * back during 1386 | * serialization, \c false to discard comments. 1387 | * This parameter is ignored if 1388 | * Features::allowComments_ 1389 | * is \c false. 1390 | * \return \c true if the document was successfully parsed, \c false if an 1391 | * error occurred. 1392 | */ 1393 | bool 1394 | parse(const std::string& document, Value& root, bool collectComments = true); 1395 | 1396 | /** \brief Read a Value from a JSON 1397 | document. 1398 | * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the 1399 | document to read. 1400 | * \param endDoc Pointer on the end of the UTF-8 encoded string of the 1401 | document to read. 1402 | * Must be >= beginDoc. 1403 | * \param root [out] Contains the root value of the document if it was 1404 | * successfully parsed. 1405 | * \param collectComments \c true to collect comment and allow writing them 1406 | back during 1407 | * serialization, \c false to discard comments. 1408 | * This parameter is ignored if 1409 | Features::allowComments_ 1410 | * is \c false. 1411 | * \return \c true if the document was successfully parsed, \c false if an 1412 | error occurred. 1413 | */ 1414 | bool parse(const char* beginDoc, 1415 | const char* endDoc, 1416 | Value& root, 1417 | bool collectComments = true); 1418 | 1419 | /// \brief Parse from input stream. 1420 | /// \see Json::operator>>(std::istream&, Json::Value&). 1421 | bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); 1422 | 1423 | /** \brief Returns a user friendly string that list errors in the parsed 1424 | * document. 1425 | * \return Formatted error message with the list of errors with their location 1426 | * in 1427 | * the parsed document. An empty string is returned if no error 1428 | * occurred 1429 | * during parsing. 1430 | * \deprecated Use getFormattedErrorMessages() instead (typo fix). 1431 | */ 1432 | JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") 1433 | JSONCPP_STRING getFormatedErrorMessages() const; 1434 | 1435 | /** \brief Returns a user friendly string that list errors in the parsed 1436 | * document. 1437 | * \return Formatted error message with the list of errors with their location 1438 | * in 1439 | * the parsed document. An empty string is returned if no error 1440 | * occurred 1441 | * during parsing. 1442 | */ 1443 | JSONCPP_STRING getFormattedErrorMessages() const; 1444 | 1445 | /** \brief Returns a vector of structured erros encounted while parsing. 1446 | * \return A (possibly empty) vector of StructuredError objects. Currently 1447 | * only one error can be returned, but the caller should tolerate 1448 | * multiple 1449 | * errors. This can occur if the parser recovers from a non-fatal 1450 | * parse error and then encounters additional errors. 1451 | */ 1452 | std::vector getStructuredErrors() const; 1453 | 1454 | /** \brief Add a semantic error message. 1455 | * \param value JSON Value location associated with the error 1456 | * \param message The error message. 1457 | * \return \c true if the error was successfully added, \c false if the 1458 | * Value offset exceeds the document size. 1459 | */ 1460 | bool pushError(const Value& value, const JSONCPP_STRING& message); 1461 | 1462 | /** \brief Add a semantic error message with extra context. 1463 | * \param value JSON Value location associated with the error 1464 | * \param message The error message. 1465 | * \param extra Additional JSON Value location to contextualize the error 1466 | * \return \c true if the error was successfully added, \c false if either 1467 | * Value offset exceeds the document size. 1468 | */ 1469 | bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); 1470 | 1471 | /** \brief Return whether there are any errors. 1472 | * \return \c true if there are no errors to report \c false if 1473 | * errors have occurred. 1474 | */ 1475 | bool good() const; 1476 | 1477 | private: 1478 | enum TokenType { 1479 | tokenEndOfStream = 0, 1480 | tokenObjectBegin, 1481 | tokenObjectEnd, 1482 | tokenArrayBegin, 1483 | tokenArrayEnd, 1484 | tokenString, 1485 | tokenNumber, 1486 | tokenTrue, 1487 | tokenFalse, 1488 | tokenNull, 1489 | tokenArraySeparator, 1490 | tokenMemberSeparator, 1491 | tokenComment, 1492 | tokenError 1493 | }; 1494 | 1495 | class Token { 1496 | public: 1497 | TokenType type_; 1498 | Location start_; 1499 | Location end_; 1500 | }; 1501 | 1502 | class ErrorInfo { 1503 | public: 1504 | Token token_; 1505 | JSONCPP_STRING message_; 1506 | Location extra_; 1507 | }; 1508 | 1509 | typedef std::deque Errors; 1510 | 1511 | bool readToken(Token& token); 1512 | void skipSpaces(); 1513 | bool match(Location pattern, int patternLength); 1514 | bool readComment(); 1515 | bool readCStyleComment(); 1516 | bool readCppStyleComment(); 1517 | bool readString(); 1518 | void readNumber(); 1519 | bool readValue(); 1520 | bool readObject(Token& token); 1521 | bool readArray(Token& token); 1522 | bool decodeNumber(Token& token); 1523 | bool decodeNumber(Token& token, Value& decoded); 1524 | bool decodeString(Token& token); 1525 | bool decodeString(Token& token, JSONCPP_STRING& decoded); 1526 | bool decodeDouble(Token& token); 1527 | bool decodeDouble(Token& token, Value& decoded); 1528 | bool decodeUnicodeCodePoint(Token& token, 1529 | Location& current, 1530 | Location end, 1531 | unsigned int& unicode); 1532 | bool decodeUnicodeEscapeSequence(Token& token, 1533 | Location& current, 1534 | Location end, 1535 | unsigned int& unicode); 1536 | bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); 1537 | bool recoverFromError(TokenType skipUntilToken); 1538 | bool addErrorAndRecover(const JSONCPP_STRING& message, 1539 | Token& token, 1540 | TokenType skipUntilToken); 1541 | void skipUntilSpace(); 1542 | Value& currentValue(); 1543 | Char getNextChar(); 1544 | void 1545 | getLocationLineAndColumn(Location location, int& line, int& column) const; 1546 | JSONCPP_STRING getLocationLineAndColumn(Location location) const; 1547 | void addComment(Location begin, Location end, CommentPlacement placement); 1548 | void skipCommentTokens(Token& token); 1549 | 1550 | typedef std::stack Nodes; 1551 | Nodes nodes_; 1552 | Errors errors_; 1553 | JSONCPP_STRING document_; 1554 | Location begin_; 1555 | Location end_; 1556 | Location current_; 1557 | Location lastValueEnd_; 1558 | Value* lastValue_; 1559 | JSONCPP_STRING commentsBefore_; 1560 | Features features_; 1561 | bool collectComments_; 1562 | }; // Reader 1563 | 1564 | /** Interface for reading JSON from a char array. 1565 | */ 1566 | class JSON_API CharReader { 1567 | public: 1568 | virtual ~CharReader() {} 1569 | /** \brief Read a Value from a JSON 1570 | document. 1571 | * The document must be a UTF-8 encoded string containing the document to read. 1572 | * 1573 | * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the 1574 | document to read. 1575 | * \param endDoc Pointer on the end of the UTF-8 encoded string of the 1576 | document to read. 1577 | * Must be >= beginDoc. 1578 | * \param root [out] Contains the root value of the document if it was 1579 | * successfully parsed. 1580 | * \param errs [out] Formatted error messages (if not NULL) 1581 | * a user friendly string that lists errors in the parsed 1582 | * document. 1583 | * \return \c true if the document was successfully parsed, \c false if an 1584 | error occurred. 1585 | */ 1586 | virtual bool parse( 1587 | char const* beginDoc, char const* endDoc, 1588 | Value* root, JSONCPP_STRING* errs) = 0; 1589 | 1590 | class JSON_API Factory { 1591 | public: 1592 | virtual ~Factory() {} 1593 | /** \brief Allocate a CharReader via operator new(). 1594 | * \throw std::exception if something goes wrong (e.g. invalid settings) 1595 | */ 1596 | virtual CharReader* newCharReader() const = 0; 1597 | }; // Factory 1598 | }; // CharReader 1599 | 1600 | /** \brief Build a CharReader implementation. 1601 | 1602 | Usage: 1603 | \code 1604 | using namespace Json; 1605 | CharReaderBuilder builder; 1606 | builder["collectComments"] = false; 1607 | Value value; 1608 | JSONCPP_STRING errs; 1609 | bool ok = parseFromStream(builder, std::cin, &value, &errs); 1610 | \endcode 1611 | */ 1612 | class JSON_API CharReaderBuilder : public CharReader::Factory { 1613 | public: 1614 | // Note: We use a Json::Value so that we can add data-members to this class 1615 | // without a major version bump. 1616 | /** Configuration of this builder. 1617 | These are case-sensitive. 1618 | Available settings (case-sensitive): 1619 | - `"collectComments": false or true` 1620 | - true to collect comment and allow writing them 1621 | back during serialization, false to discard comments. 1622 | This parameter is ignored if allowComments is false. 1623 | - `"allowComments": false or true` 1624 | - true if comments are allowed. 1625 | - `"strictRoot": false or true` 1626 | - true if root must be either an array or an object value 1627 | - `"allowDroppedNullPlaceholders": false or true` 1628 | - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) 1629 | - `"allowNumericKeys": false or true` 1630 | - true if numeric object keys are allowed. 1631 | - `"allowSingleQuotes": false or true` 1632 | - true if '' are allowed for strings (both keys and values) 1633 | - `"stackLimit": integer` 1634 | - Exceeding stackLimit (recursive depth of `readValue()`) will 1635 | cause an exception. 1636 | - This is a security issue (seg-faults caused by deeply nested JSON), 1637 | so the default is low. 1638 | - `"failIfExtra": false or true` 1639 | - If true, `parse()` returns false when extra non-whitespace trails 1640 | the JSON value in the input string. 1641 | - `"rejectDupKeys": false or true` 1642 | - If true, `parse()` returns false when a key is duplicated within an object. 1643 | - `"allowSpecialFloats": false or true` 1644 | - If true, special float values (NaNs and infinities) are allowed 1645 | and their values are lossfree restorable. 1646 | 1647 | You can examine 'settings_` yourself 1648 | to see the defaults. You can also write and read them just like any 1649 | JSON Value. 1650 | \sa setDefaults() 1651 | */ 1652 | Json::Value settings_; 1653 | 1654 | CharReaderBuilder(); 1655 | ~CharReaderBuilder() JSONCPP_OVERRIDE; 1656 | 1657 | CharReader* newCharReader() const JSONCPP_OVERRIDE; 1658 | 1659 | /** \return true if 'settings' are legal and consistent; 1660 | * otherwise, indicate bad settings via 'invalid'. 1661 | */ 1662 | bool validate(Json::Value* invalid) const; 1663 | 1664 | /** A simple way to update a specific setting. 1665 | */ 1666 | Value& operator[](JSONCPP_STRING key); 1667 | 1668 | /** Called by ctor, but you can use this to reset settings_. 1669 | * \pre 'settings' != NULL (but Json::null is fine) 1670 | * \remark Defaults: 1671 | * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults 1672 | */ 1673 | static void setDefaults(Json::Value* settings); 1674 | /** Same as old Features::strictMode(). 1675 | * \pre 'settings' != NULL (but Json::null is fine) 1676 | * \remark Defaults: 1677 | * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode 1678 | */ 1679 | static void strictMode(Json::Value* settings); 1680 | }; 1681 | 1682 | /** Consume entire stream and use its begin/end. 1683 | * Someday we might have a real StreamReader, but for now this 1684 | * is convenient. 1685 | */ 1686 | bool JSON_API parseFromStream( 1687 | CharReader::Factory const&, 1688 | JSONCPP_ISTREAM&, 1689 | Value* root, std::string* errs); 1690 | 1691 | /** \brief Read from 'sin' into 'root'. 1692 | 1693 | Always keep comments from the input JSON. 1694 | 1695 | This can be used to read a file into a particular sub-object. 1696 | For example: 1697 | \code 1698 | Json::Value root; 1699 | cin >> root["dir"]["file"]; 1700 | cout << root; 1701 | \endcode 1702 | Result: 1703 | \verbatim 1704 | { 1705 | "dir": { 1706 | "file": { 1707 | // The input stream JSON would be nested here. 1708 | } 1709 | } 1710 | } 1711 | \endverbatim 1712 | \throw std::exception on parse error. 1713 | \see Json::operator<<() 1714 | */ 1715 | JSON_API JSONCPP_ISTREAM& operator >> (JSONCPP_ISTREAM&, Value&); 1716 | 1717 | } // namespace Json 1718 | 1719 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1720 | #pragma warning(pop) 1721 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1722 | 1723 | #endif // CPPTL_JSON_READER_H_INCLUDED 1724 | 1725 | // ////////////////////////////////////////////////////////////////////// 1726 | // End of content of file: include/json/reader.h 1727 | // ////////////////////////////////////////////////////////////////////// 1728 | 1729 | 1730 | 1731 | 1732 | 1733 | 1734 | // ////////////////////////////////////////////////////////////////////// 1735 | // Beginning of content of file: include/json/writer.h 1736 | // ////////////////////////////////////////////////////////////////////// 1737 | 1738 | // Copyright 2007-2010 Baptiste Lepilleur 1739 | // Distributed under MIT license, or public domain if desired and 1740 | // recognized in your jurisdiction. 1741 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 1742 | 1743 | #ifndef JSON_WRITER_H_INCLUDED 1744 | #define JSON_WRITER_H_INCLUDED 1745 | 1746 | #if !defined(JSON_IS_AMALGAMATION) 1747 | #include "value.h" 1748 | #endif // if !defined(JSON_IS_AMALGAMATION) 1749 | #include 1750 | #include 1751 | #include 1752 | 1753 | // Disable warning C4251: : needs to have dll-interface to 1754 | // be used by... 1755 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1756 | #pragma warning(push) 1757 | #pragma warning(disable : 4251) 1758 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 1759 | 1760 | namespace Json { 1761 | 1762 | class Value; 1763 | 1764 | /** 1765 | 1766 | Usage: 1767 | \code 1768 | using namespace Json; 1769 | void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { 1770 | std::unique_ptr const writer( 1771 | factory.newStreamWriter()); 1772 | writer->write(value, &std::cout); 1773 | std::cout << std::endl; // add lf and flush 1774 | } 1775 | \endcode 1776 | */ 1777 | class JSON_API StreamWriter { 1778 | protected: 1779 | JSONCPP_OSTREAM* sout_; // not owned; will not delete 1780 | public: 1781 | StreamWriter(); 1782 | virtual ~StreamWriter(); 1783 | /** Write Value into document as configured in sub-class. 1784 | Do not take ownership of sout, but maintain a reference during function. 1785 | \pre sout != NULL 1786 | \return zero on success (For now, we always return zero, so check the stream instead.) 1787 | \throw std::exception possibly, depending on configuration 1788 | */ 1789 | virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; 1790 | 1791 | /** \brief A simple abstract factory. 1792 | */ 1793 | class JSON_API Factory { 1794 | public: 1795 | virtual ~Factory(); 1796 | /** \brief Allocate a CharReader via operator new(). 1797 | * \throw std::exception if something goes wrong (e.g. invalid settings) 1798 | */ 1799 | virtual StreamWriter* newStreamWriter() const = 0; 1800 | }; // Factory 1801 | }; // StreamWriter 1802 | 1803 | /** \brief Write into stringstream, then return string, for convenience. 1804 | * A StreamWriter will be created from the factory, used, and then deleted. 1805 | */ 1806 | JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); 1807 | 1808 | 1809 | /** \brief Build a StreamWriter implementation. 1810 | 1811 | Usage: 1812 | \code 1813 | using namespace Json; 1814 | Value value = ...; 1815 | StreamWriterBuilder builder; 1816 | builder["commentStyle"] = "None"; 1817 | builder["indentation"] = " "; // or whatever you like 1818 | std::unique_ptr writer( 1819 | builder.newStreamWriter()); 1820 | writer->write(value, &std::cout); 1821 | std::cout << std::endl; // add lf and flush 1822 | \endcode 1823 | */ 1824 | class JSON_API StreamWriterBuilder : public StreamWriter::Factory { 1825 | public: 1826 | // Note: We use a Json::Value so that we can add data-members to this class 1827 | // without a major version bump. 1828 | /** Configuration of this builder. 1829 | Available settings (case-sensitive): 1830 | - "commentStyle": "None" or "All" 1831 | - "indentation": "" 1832 | - "enableYAMLCompatibility": false or true 1833 | - slightly change the whitespace around colons 1834 | - "dropNullPlaceholders": false or true 1835 | - Drop the "null" string from the writer's output for nullValues. 1836 | Strictly speaking, this is not valid JSON. But when the output is being 1837 | fed to a browser's Javascript, it makes for smaller output and the 1838 | browser can handle the output just fine. 1839 | - "useSpecialFloats": false or true 1840 | - If true, outputs non-finite floating point values in the following way: 1841 | NaN values as "NaN", positive infinity as "Infinity", and negative infinity 1842 | as "-Infinity". 1843 | 1844 | You can examine 'settings_` yourself 1845 | to see the defaults. You can also write and read them just like any 1846 | JSON Value. 1847 | \sa setDefaults() 1848 | */ 1849 | Json::Value settings_; 1850 | 1851 | StreamWriterBuilder(); 1852 | ~StreamWriterBuilder() JSONCPP_OVERRIDE; 1853 | 1854 | /** 1855 | * \throw std::exception if something goes wrong (e.g. invalid settings) 1856 | */ 1857 | StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; 1858 | 1859 | /** \return true if 'settings' are legal and consistent; 1860 | * otherwise, indicate bad settings via 'invalid'. 1861 | */ 1862 | bool validate(Json::Value* invalid) const; 1863 | /** A simple way to update a specific setting. 1864 | */ 1865 | Value& operator[](JSONCPP_STRING key); 1866 | 1867 | /** Called by ctor, but you can use this to reset settings_. 1868 | * \pre 'settings' != NULL (but Json::null is fine) 1869 | * \remark Defaults: 1870 | * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults 1871 | */ 1872 | static void setDefaults(Json::Value* settings); 1873 | }; 1874 | 1875 | /** \brief Abstract class for writers. 1876 | * \deprecated Use StreamWriter. (And really, this is an implementation detail.) 1877 | */ 1878 | class JSON_API Writer { 1879 | public: 1880 | virtual ~Writer(); 1881 | 1882 | virtual JSONCPP_STRING write(const Value& root) = 0; 1883 | }; 1884 | 1885 | /** \brief Outputs a Value in JSON format 1886 | *without formatting (not human friendly). 1887 | * 1888 | * The JSON document is written in a single line. It is not intended for 'human' 1889 | *consumption, 1890 | * but may be usefull to support feature such as RPC where bandwith is limited. 1891 | * \sa Reader, Value 1892 | * \deprecated Use StreamWriterBuilder. 1893 | */ 1894 | class JSON_API FastWriter : public Writer { 1895 | 1896 | public: 1897 | FastWriter(); 1898 | ~FastWriter() JSONCPP_OVERRIDE {} 1899 | 1900 | void enableYAMLCompatibility(); 1901 | 1902 | /** \brief Drop the "null" string from the writer's output for nullValues. 1903 | * Strictly speaking, this is not valid JSON. But when the output is being 1904 | * fed to a browser's Javascript, it makes for smaller output and the 1905 | * browser can handle the output just fine. 1906 | */ 1907 | void dropNullPlaceholders(); 1908 | 1909 | void omitEndingLineFeed(); 1910 | 1911 | public: // overridden from Writer 1912 | JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; 1913 | 1914 | private: 1915 | void writeValue(const Value& value); 1916 | 1917 | JSONCPP_STRING document_; 1918 | bool yamlCompatiblityEnabled_; 1919 | bool dropNullPlaceholders_; 1920 | bool omitEndingLineFeed_; 1921 | }; 1922 | 1923 | /** \brief Writes a Value in JSON format in a 1924 | *human friendly way. 1925 | * 1926 | * The rules for line break and indent are as follow: 1927 | * - Object value: 1928 | * - if empty then print {} without indent and line break 1929 | * - if not empty the print '{', line break & indent, print one value per 1930 | *line 1931 | * and then unindent and line break and print '}'. 1932 | * - Array value: 1933 | * - if empty then print [] without indent and line break 1934 | * - if the array contains no object value, empty array or some other value 1935 | *types, 1936 | * and all the values fit on one lines, then print the array on a single 1937 | *line. 1938 | * - otherwise, it the values do not fit on one line, or the array contains 1939 | * object or non empty array, then print one value per line. 1940 | * 1941 | * If the Value have comments then they are outputed according to their 1942 | *#CommentPlacement. 1943 | * 1944 | * \sa Reader, Value, Value::setComment() 1945 | * \deprecated Use StreamWriterBuilder. 1946 | */ 1947 | class JSON_API StyledWriter : public Writer { 1948 | public: 1949 | StyledWriter(); 1950 | ~StyledWriter() JSONCPP_OVERRIDE {} 1951 | 1952 | public: // overridden from Writer 1953 | /** \brief Serialize a Value in JSON format. 1954 | * \param root Value to serialize. 1955 | * \return String containing the JSON document that represents the root value. 1956 | */ 1957 | JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; 1958 | 1959 | private: 1960 | void writeValue(const Value& value); 1961 | void writeArrayValue(const Value& value); 1962 | bool isMultineArray(const Value& value); 1963 | void pushValue(const JSONCPP_STRING& value); 1964 | void writeIndent(); 1965 | void writeWithIndent(const JSONCPP_STRING& value); 1966 | void indent(); 1967 | void unindent(); 1968 | void writeCommentBeforeValue(const Value& root); 1969 | void writeCommentAfterValueOnSameLine(const Value& root); 1970 | bool hasCommentForValue(const Value& value); 1971 | static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); 1972 | 1973 | typedef std::vector ChildValues; 1974 | 1975 | ChildValues childValues_; 1976 | JSONCPP_STRING document_; 1977 | JSONCPP_STRING indentString_; 1978 | unsigned int rightMargin_; 1979 | unsigned int indentSize_; 1980 | bool addChildValues_; 1981 | }; 1982 | 1983 | /** \brief Writes a Value in JSON format in a 1984 | human friendly way, 1985 | to a stream rather than to a string. 1986 | * 1987 | * The rules for line break and indent are as follow: 1988 | * - Object value: 1989 | * - if empty then print {} without indent and line break 1990 | * - if not empty the print '{', line break & indent, print one value per 1991 | line 1992 | * and then unindent and line break and print '}'. 1993 | * - Array value: 1994 | * - if empty then print [] without indent and line break 1995 | * - if the array contains no object value, empty array or some other value 1996 | types, 1997 | * and all the values fit on one lines, then print the array on a single 1998 | line. 1999 | * - otherwise, it the values do not fit on one line, or the array contains 2000 | * object or non empty array, then print one value per line. 2001 | * 2002 | * If the Value have comments then they are outputed according to their 2003 | #CommentPlacement. 2004 | * 2005 | * \param indentation Each level will be indented by this amount extra. 2006 | * \sa Reader, Value, Value::setComment() 2007 | * \deprecated Use StreamWriterBuilder. 2008 | */ 2009 | class JSON_API StyledStreamWriter { 2010 | public: 2011 | StyledStreamWriter(JSONCPP_STRING indentation = "\t"); 2012 | ~StyledStreamWriter() {} 2013 | 2014 | public: 2015 | /** \brief Serialize a Value in JSON format. 2016 | * \param out Stream to write to. (Can be ostringstream, e.g.) 2017 | * \param root Value to serialize. 2018 | * \note There is no point in deriving from Writer, since write() should not 2019 | * return a value. 2020 | */ 2021 | void write(JSONCPP_OSTREAM& out, const Value& root); 2022 | 2023 | private: 2024 | void writeValue(const Value& value); 2025 | void writeArrayValue(const Value& value); 2026 | bool isMultineArray(const Value& value); 2027 | void pushValue(const JSONCPP_STRING& value); 2028 | void writeIndent(); 2029 | void writeWithIndent(const JSONCPP_STRING& value); 2030 | void indent(); 2031 | void unindent(); 2032 | void writeCommentBeforeValue(const Value& root); 2033 | void writeCommentAfterValueOnSameLine(const Value& root); 2034 | bool hasCommentForValue(const Value& value); 2035 | static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); 2036 | 2037 | typedef std::vector ChildValues; 2038 | 2039 | ChildValues childValues_; 2040 | JSONCPP_OSTREAM* document_; 2041 | JSONCPP_STRING indentString_; 2042 | unsigned int rightMargin_; 2043 | JSONCPP_STRING indentation_; 2044 | bool addChildValues_ : 1; 2045 | bool indented_ : 1; 2046 | }; 2047 | 2048 | #if defined(JSON_HAS_INT64) 2049 | JSONCPP_STRING JSON_API valueToString(Int value); 2050 | JSONCPP_STRING JSON_API valueToString(UInt value); 2051 | #endif // if defined(JSON_HAS_INT64) 2052 | JSONCPP_STRING JSON_API valueToString(LargestInt value); 2053 | JSONCPP_STRING JSON_API valueToString(LargestUInt value); 2054 | JSONCPP_STRING JSON_API valueToString(double value); 2055 | JSONCPP_STRING JSON_API valueToString(bool value); 2056 | JSONCPP_STRING JSON_API valueToQuotedString(const char* value); 2057 | 2058 | /// \brief Output using the StyledStreamWriter. 2059 | /// \see Json::operator>>() 2060 | JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); 2061 | 2062 | } // namespace Json 2063 | 2064 | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 2065 | #pragma warning(pop) 2066 | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 2067 | 2068 | #endif // JSON_WRITER_H_INCLUDED 2069 | 2070 | // ////////////////////////////////////////////////////////////////////// 2071 | // End of content of file: include/json/writer.h 2072 | // ////////////////////////////////////////////////////////////////////// 2073 | 2074 | 2075 | 2076 | 2077 | 2078 | 2079 | // ////////////////////////////////////////////////////////////////////// 2080 | // Beginning of content of file: include/json/assertions.h 2081 | // ////////////////////////////////////////////////////////////////////// 2082 | 2083 | // Copyright 2007-2010 Baptiste Lepilleur 2084 | // Distributed under MIT license, or public domain if desired and 2085 | // recognized in your jurisdiction. 2086 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 2087 | 2088 | #ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED 2089 | #define CPPTL_JSON_ASSERTIONS_H_INCLUDED 2090 | 2091 | #include 2092 | #include 2093 | 2094 | #if !defined(JSON_IS_AMALGAMATION) 2095 | #include "config.h" 2096 | #endif // if !defined(JSON_IS_AMALGAMATION) 2097 | 2098 | /** It should not be possible for a maliciously designed file to 2099 | * cause an abort() or seg-fault, so these macros are used only 2100 | * for pre-condition violations and internal logic errors. 2101 | */ 2102 | #if JSON_USE_EXCEPTION 2103 | 2104 | // @todo <= add detail about condition in exception 2105 | # define JSON_ASSERT(condition) \ 2106 | {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} 2107 | 2108 | # define JSON_FAIL_MESSAGE(message) \ 2109 | { \ 2110 | JSONCPP_OSTRINGSTREAM oss; oss << message; \ 2111 | Json::throwLogicError(oss.str()); \ 2112 | abort(); \ 2113 | } 2114 | 2115 | #else // JSON_USE_EXCEPTION 2116 | 2117 | #ifdef PIN_CRT 2118 | # define JSON_ASSERT(condition) assert(condition) 2119 | #else 2120 | #include "pin.h" 2121 | #define JSON_ASSERT(condition) ASSERT(condition) 2122 | #endif 2123 | 2124 | // The call to assert() will show the failure message in debug builds. In 2125 | // release builds we abort, for a core-dump or debugger. 2126 | # define JSON_FAIL_MESSAGE(message) \ 2127 | { \ 2128 | JSONCPP_OSTRINGSTREAM oss; oss << message; \ 2129 | JSON_ASSERT(false && oss.str().c_str()); \ 2130 | abort(); \ 2131 | } 2132 | 2133 | 2134 | #endif 2135 | 2136 | #define JSON_ASSERT_MESSAGE(condition, message) \ 2137 | if (!(condition)) { \ 2138 | JSON_FAIL_MESSAGE(message); \ 2139 | } 2140 | 2141 | #endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED 2142 | 2143 | // ////////////////////////////////////////////////////////////////////// 2144 | // End of content of file: include/json/assertions.h 2145 | // ////////////////////////////////////////////////////////////////////// 2146 | 2147 | 2148 | 2149 | 2150 | 2151 | #endif //ifndef JSON_AMALGATED_H_INCLUDED -------------------------------------------------------------------------------- /icount/loggers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define INFO_LEVEL 1 4 | #define DEBUG_LEVEL 0 5 | 6 | #if INFO_LEVEL 7 | #define INFO(format, ...) { fprintf(stdout, format, __VA_ARGS__); } 8 | #else 9 | #define INFO(format, ...) { do {} while(0); } 10 | #endif 11 | 12 | #if DEBUG_LEVEL 13 | #define DEBUG(format, ...) { fprintf(stdout, format, __VA_ARGS__); fflush(stdout); } 14 | #else 15 | #define DEBUG(format, ...) { do {} while(0); } 16 | #endif 17 | 18 | #define ERROR(format, ...) { fprintf(stderr, format, __VA_ARGS__); } 19 | 20 | #define REPORT(format, ...) { fprintf(stdout, format, __VA_ARGS__); } -------------------------------------------------------------------------------- /icount/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "pin.H" 5 | #include "main.h" 6 | #include "callbacks.h" 7 | #include "flusher.h" 8 | 9 | #include "dump.h" 10 | #include "report.h" 11 | #include "loggers.h" 12 | #include "utils.h" 13 | #include "error_handlers.h" 14 | 15 | TLS_KEY tls_key = INVALID_TLS_KEY; 16 | 17 | PIN_LOCK pin_lock; 18 | PIN_MUTEX flusher_req_mutex; 19 | PIN_SEMAPHORE flusher_ready_sem; 20 | PIN_THREAD_UID flusher_uid; 21 | 22 | /** Custom options for our PIN tool **/ 23 | KNOB KnobIsBuffered(KNOB_MODE_WRITEONCE, "pintool", 24 | "buffered", "false", "whether or not the trace is buffered"); 25 | KNOB KnobIsThreadFlushed(KNOB_MODE_WRITEONCE, "pintool", 26 | "thread_flushed", "false", "whether or not the trace has a thread for flushing"); 27 | KNOB KnobTraceLimit(KNOB_MODE_WRITEONCE, "pintool", 28 | "trace_limit", "0", "size of the trace limit"); 29 | KNOB KnobThreadBufferSize(KNOB_MODE_WRITEONCE, "pintool", 30 | "thread_buffer_size", "0", "size of the per-thread buffer"); 31 | KNOB KnobFavorMainThread(KNOB_MODE_WRITEONCE, "pintool", 32 | "favor_main_thread", "false", "allocate a quarter of thread buffer for thread that are not 0"); 33 | KNOB KnobPerformanceTag(KNOB_MODE_WRITEONCE, "pintool", 34 | "tag", "", "tag for the performance report"); 35 | 36 | // Stats 37 | time_t total_time; 38 | time_t total_sync_time; 39 | time_t total_wait_time; 40 | time_t total_flusher_time; 41 | time_t total_flusher_flushing_time; 42 | time_t total_flushing_time; 43 | time_t total_writed_intervals_creation_time; 44 | time_t total_wxorx_check_time; 45 | 46 | size_t spawned_threads_no; 47 | size_t trace_size; 48 | size_t total_flushes; 49 | proc_info_t* proc_info; 50 | 51 | // Configs 52 | bool isBuffered; 53 | bool isThreadFlushed; 54 | bool isMainThreadFavored; 55 | size_t trace_limit; 56 | size_t thread_buffer_size; 57 | string performance_tag; 58 | 59 | bool isFirstIns = true; 60 | const char* prog_name; 61 | 62 | trace_t* traces[THREADS_MAX_NO]; 63 | FILE* files[THREADS_MAX_NO]; 64 | bool hasReachedTraceLimit[THREADS_MAX_NO]; 65 | 66 | // Online 67 | upx_info_t* upx_info; 68 | bool isBinaryPacked = true; 69 | FILE* upx_dump_file; 70 | list> written_mem_intervals; 71 | pair main_img_memory(0, 0); 72 | pair text_sec_memory(0, 0); 73 | 74 | void waitFlushEnd(doub_buf_trace_t* dbt, THREADID thread_idx) { 75 | time_t tv; 76 | INFO("[*]{Thread %d} Waiting for flush to be finished\n", thread_idx); 77 | START_STOPWATCH(tv); 78 | PIN_SemaphoreWait(&dbt->end_flush_sem); 79 | total_wait_time += GET_STOPWATCH_LAP(tv); 80 | } 81 | 82 | void requestFlush(doub_buf_trace_t* dbt, FILE* f, THREADID thread_idx) { 83 | INFO("[*]{Thread %d} Requested a flush\n", thread_idx); 84 | flusher::requesting_thread_idx = thread_idx; 85 | flusher::dbt = dbt; 86 | flusher::f = f; 87 | PIN_SemaphoreClear(&dbt->end_flush_sem); 88 | PIN_SemaphoreSet(&flusher::flusher_sem); 89 | } 90 | 91 | /* Here a request to the flusher might be carried out */ 92 | bool traceLimitGuard(trace_t* trace, size_t buf_len, THREADID thread_idx) { 93 | // If we reached the trace limit let's stop tracing 94 | if (trace_size + buf_len > trace_limit) { 95 | hasReachedTraceLimit[thread_idx] = true; 96 | return true; 97 | } 98 | // If we are in flushed mode no action is required 99 | if (!isBuffered) return false; 100 | 101 | // If we have not reached the main buffer maximum size no action is required 102 | if (trace->cursor + buf_len <= trace->buf_size) return false; 103 | 104 | if (!isThreadFlushed) { 105 | time_t tv; 106 | INFO("[*] Thread buffer limit reached, flushing\n"); 107 | if (!thread_idx) START_STOPWATCH(tv); 108 | flushTraceToFile(files[thread_idx], trace->buf, trace->cursor); 109 | if (!thread_idx) total_flushing_time += GET_STOPWATCH_LAP(tv); 110 | trace->cursor = 0; 111 | } else { 112 | time_t tv; 113 | if (!thread_idx) 114 | START_STOPWATCH(tv); 115 | // Thread buffer limit has been reached, and flusher thread option is on 116 | doub_buf_trace_t* dbt = (doub_buf_trace_t*) trace; 117 | if (dbt->isFlushBufEmpty) { 118 | // Let's switch the buffers 119 | dbt->flush_buf = trace->buf; 120 | dbt->flush_buf_len = trace->cursor; 121 | trace->buf = (char*) malloc(sizeof(char) * trace->buf_size); 122 | MALLOC_ERROR_HANDLER(trace->buf, "[x] Not enough space to allocate another buffer for the trace\n"); 123 | trace->cursor = 0; 124 | dbt->isFlushBufEmpty = false; 125 | /* We try to gain the privilege to talk with the flusher 126 | On success => fire the flush 127 | On fail => move trace in a flush_buf pointer and try again later*/ 128 | if (PIN_MutexTryLock(&flusher_req_mutex)) { 129 | requestFlush(dbt, files[thread_idx], thread_idx); 130 | } else { 131 | INFO("[*]{Thread %d} prepared for flush, trying next time\n", thread_idx); 132 | } 133 | } else { 134 | /* We need space to keep on writing 135 | Already asked a flush => wait for the flusher to end the flush 136 | Not asked a flush yet => wait to gain privilege to ask for it */ 137 | if (dbt->isFlushing) { 138 | waitFlushEnd(dbt, thread_idx); 139 | } else { 140 | PIN_MutexLock(&flusher_req_mutex); 141 | requestFlush(dbt, files[thread_idx], thread_idx); 142 | } 143 | } 144 | if (!thread_idx) 145 | total_sync_time += GET_STOPWATCH_LAP(tv); 146 | } 147 | return false; 148 | } 149 | 150 | void Img(IMG img, void* v) { 151 | reportImage(img); 152 | if (!IMG_IsMainExecutable(img)) { 153 | //INFO("[+] %s loaded at 0x%08x\n", IMG_Name(img).c_str(), IMG_StartAddress(img)); 154 | return; 155 | } 156 | 157 | reportMainImage(img); 158 | 159 | INFO("[+] Main image %s loaded at 0x%08x\n", IMG_Name(img).c_str(), IMG_StartAddress(img)); 160 | main_img_memory = make_pair(IMG_LowAddress(img), IMG_HighAddress(img)); 161 | // Find .text section address interval 162 | for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec)) { 163 | string sec_name = SEC_Name(sec); 164 | if (sec_name == TEXT_SEC_NAME) { 165 | isBinaryPacked = false; 166 | text_sec_memory = make_pair(SEC_Address(sec), SEC_Address(sec) + SEC_Size(sec)); 167 | } 168 | } 169 | } 170 | 171 | void Ins(INS ins, void* v) { 172 | ADDRINT ins_addr = INS_Address(ins); 173 | // TODO: Remove this comment to create the CFG 174 | if (!IN_RANGE(ins_addr, main_img_memory.first, main_img_memory.second)) return; 175 | 176 | string disasm_ins_s = INS_Disassemble(ins); 177 | /* Allocate enough space to save 178 | - Disassembled instruction (n bytes) 179 | - INS_DELIMITER (1 byte) 180 | - 0 terminator (1 byte) 181 | */ 182 | uint32_t disasm_ins_len = strlen(disasm_ins_s.c_str()) + 2; 183 | char* disasm_ins = (char*) malloc(sizeof(char) * (disasm_ins_len)); 184 | MALLOC_ERROR_HANDLER(disasm_ins, "[x] Not enough space to allocate disassembled_ins\n"); 185 | disasm_ins[0] = INS_DELIMITER; 186 | disasm_ins[disasm_ins_len - 1] = '\0'; 187 | strcpy(disasm_ins + 1, disasm_ins_s.c_str()); 188 | if (isFirstIns) { 189 | isFirstIns = false; 190 | strcpy(disasm_ins, disasm_ins + 1); 191 | } 192 | 193 | /* There should be a better way to find the EP */ 194 | /*INS_InsertCall(ins, IPOINT_BEFORE, 195 | (AFUNPTR) INS_EntryPoint, 196 | IARG_INST_PTR, 197 | IARG_THREAD_ID, 198 | IARG_END);*/ 199 | 200 | if (INS_IsBranchOrCall(ins)) { 201 | /*INS_InsertCall(ins, IPOINT_BEFORE, 202 | (AFUNPTR) INS_Analysis, 203 | IARG_PTR, 204 | disasm_ins, 205 | IARG_UINT32, 206 | disasm_ins_len, 207 | IARG_THREAD_ID, 208 | IARG_END);*/ 209 | 210 | 211 | ADDRINT ins_end = INS_Address(ins) + INS_Size(ins); 212 | INS_InsertCall(ins, IPOINT_BEFORE, 213 | (AFUNPTR)INS_JumpAnalysis, 214 | IARG_ADDRINT, 215 | ins_end, 216 | IARG_BRANCH_TARGET_ADDR, 217 | IARG_BRANCH_TAKEN, 218 | IARG_THREAD_ID, 219 | IARG_END); 220 | } 221 | 222 | // FIXME: Remove this, testing only 223 | return; 224 | /* If we are in online mode, no .text section has been found and instruction 225 | in main img address */ 226 | if (isBinaryPacked && IN_RANGE(ins_addr, main_img_memory.first, main_img_memory.second)) { 227 | if (INS_Opcode(ins) == XED_ICLASS_PUSHAD || 228 | INS_Opcode(ins) == XED_ICLASS_POPAD || 229 | INS_Opcode(ins) == XED_ICLASS_JMP) { 230 | INS_InsertCall(ins, IPOINT_BEFORE, 231 | (AFUNPTR) INS_UPXEndAnalysis, 232 | IARG_UINT32, 233 | INS_Opcode(ins), 234 | IARG_END); 235 | } 236 | 237 | 238 | if (INS_IsMemoryWrite(ins)) { 239 | INS_InsertCall(ins, IPOINT_BEFORE, 240 | (AFUNPTR) INS_WriteAnalysis, 241 | IARG_MEMORYWRITE_EA, 242 | IARG_MEMORYWRITE_SIZE, 243 | IARG_END); 244 | } 245 | /*if (upx_info->metJmp) { 246 | INS_InsertCall(ins, IPOINT_BEFORE, 247 | (AFUNPTR) INS_WXorX, 248 | IARG_ADDRINT, 249 | ins_addr, 250 | IARG_PTR, 251 | disasm_ins, 252 | IARG_END); 253 | }*/ 254 | } 255 | } 256 | 257 | void ThreadStart(THREADID thread_idx, CONTEXT* ctx, INT32 flags, VOID* v) { 258 | INFO("[*] Spawned thread %d with OS_THREADID %d\n", thread_idx, PIN_GetTid()); 259 | 260 | PIN_GetLock(&pin_lock, thread_idx); 261 | /* Create output file */ 262 | char filename[TRACE_NAME_LENGTH_LIMIT] = { 0 }; 263 | sprintf(filename, "trace_%d.out", thread_idx); 264 | FILE* out = fopen(filename, "w+"); 265 | INFO("[+] Created file %s\n", filename); 266 | 267 | /* Initialize a raw trace per thread */ 268 | trace_t* trace; 269 | if (isThreadFlushed) { 270 | doub_buf_trace_t* dbt = (doub_buf_trace_t*) malloc(sizeof(doub_buf_trace_t)); 271 | dbt->flush_buf = NULL; // We do not allocate space for this since this pointer will receive the trace's buf 272 | dbt->isFlushBufEmpty = true; 273 | dbt->isFlushing = false; 274 | PIN_SemaphoreInit(&dbt->end_flush_sem); 275 | trace = (trace_t*) dbt; 276 | } else 277 | trace = (trace_t*) malloc(sizeof(trace_t*)); 278 | 279 | if (isMainThreadFavored) { 280 | if (thread_idx == 0) trace->buf_size = thread_buffer_size; 281 | else trace->buf_size = thread_buffer_size/MAIN_THREAD_FAVOR_FACTOR; 282 | } else 283 | trace->buf_size = thread_buffer_size; 284 | 285 | trace->buf = (char*) malloc(sizeof(char) * trace->buf_size); 286 | MALLOC_ERROR_HANDLER(trace->buf, "[x] Not enough space to allocate the buffer\n"); 287 | trace->cursor = 0; 288 | files[thread_idx] = out; 289 | 290 | traces[thread_idx] = trace; 291 | if (PIN_SetThreadData(tls_key, trace, thread_idx) == FALSE) { 292 | ERROR("[x] PIN_SetThreadData failed\n"); 293 | PIN_ExitProcess(1); 294 | } 295 | spawned_threads_no++; 296 | PIN_ReleaseLock(&pin_lock); 297 | } 298 | 299 | void ThreadFini(THREADID thread_idx, const CONTEXT* ctx, INT32 code, VOID* v) { 300 | trace_t* trace = (trace_t*) PIN_GetThreadData(tls_key, thread_idx); 301 | REPORT("[*]{Thread %d} Ended, trace limit reached: %d\n", thread_idx, hasReachedTraceLimit[thread_idx]); 302 | if (isThreadFlushed) { 303 | doub_buf_trace_t* dbt = (doub_buf_trace_t*) trace; 304 | if (dbt->isFlushing) { 305 | INFO("[*]{Thread %d} Flusher still on duty, waiting for it to finish\n", thread_idx); 306 | waitFlushEnd(dbt, thread_idx); 307 | } 308 | } 309 | // If there is something else left in the main buf we save it now 310 | if (trace->cursor > 0) { 311 | INFO("[*]{Thread %d} Flushing remaining %d Mb\n", thread_idx, trace->cursor / Mb); 312 | flushTraceToFile(files[thread_idx], trace->buf, trace->cursor) 313 | } 314 | fclose(files[thread_idx]); 315 | 316 | total_time += GET_STOPWATCH_LAP(total_time); 317 | INFO("[*]{Thread %d} Trace saved\n", thread_idx); 318 | } 319 | 320 | void Config() { 321 | isBuffered = KnobIsBuffered.Value(); 322 | INFO("[*] Is Buffered? %d\n", isBuffered); 323 | 324 | isThreadFlushed = KnobIsThreadFlushed.Value(); 325 | if (isThreadFlushed) isBuffered = true; 326 | INFO("[*] Is Thread flushed? %d\n", isThreadFlushed); 327 | 328 | isMainThreadFavored = KnobFavorMainThread.Value(); 329 | INFO("[*] Is main thread favored? %d\n", isMainThreadFavored); 330 | 331 | trace_limit = KnobTraceLimit.Value() > 0 ? KnobTraceLimit.Value()*Mb : TRACE_LIMIT; 332 | INFO("[*] Trace limit: %dMb\n", trace_limit/Mb); 333 | 334 | thread_buffer_size = KnobThreadBufferSize.Value() > 0 ? KnobThreadBufferSize.Value()*Mb : THREAD_BUFFER_SIZE; 335 | INFO("[*] Thread buffer size: %dMb\n", thread_buffer_size/Mb); 336 | 337 | performance_tag = KnobPerformanceTag.Value(); 338 | INFO("[*] Performance tag %s\n", performance_tag.c_str()) 339 | } 340 | 341 | void Usage() { 342 | ERROR("--- PinCFGReconstructor ---\n"); 343 | ERROR((KNOB_BASE::StringKnobSummary() + "\n").c_str()); 344 | } 345 | 346 | void ApplicationStartFunction(void* v) { 347 | START_STOPWATCH(total_time); 348 | } 349 | 350 | void PrepareForFini(void* v) { 351 | PIN_LockClient(); 352 | IMG img = IMG_FindByAddress(main_img_memory.first); 353 | ERROR_HANDLER(!IMG_Valid(img), "[x] Invalid image to dump\n"); 354 | PIN_UnlockClient(); 355 | dumpImg(img); 356 | dumpSections(img); 357 | dumpWrittenIntervals(); 358 | 359 | if (isThreadFlushed) { 360 | INFO("[*] Waiting for flusher to terminate\n"); 361 | flusher::isPoisoned = true; 362 | PIN_SemaphoreSet(&flusher::flusher_sem); 363 | PIN_WaitForThreadTermination(flusher_uid, PIN_INFINITE_TIMEOUT, NULL); 364 | } 365 | } 366 | 367 | void Fini(INT32 code, VOID *v) { 368 | REPORT("=======================\n"); 369 | REPORT("Trace finished\n"); 370 | if (isThreadFlushed) { 371 | REPORT("[i] Time spent to sync with flusher: %d ms\n", total_sync_time); 372 | REPORT("[i] Time spent waiting for flusher: %d ms\n", total_wait_time); 373 | REPORT("[i] Time the flusher was flushing: %d ms\n", total_flusher_flushing_time); 374 | REPORT("[i] Average time per flush: %d ms\n", total_flusher_flushing_time / total_flushes); 375 | REPORT("[i] Time the flusher was running: %d ms\n", total_flusher_time); 376 | } else if (isBuffered) { 377 | REPORT("[i] Time spent for flushing: %d ms\n", total_flushing_time); 378 | REPORT("[i] Average time per flush: %d ms\n", total_flushing_time / total_flushes); 379 | } 380 | if (isBinaryPacked) { 381 | REPORT("[i] OEP found at 0x%08x\n", upx_info->OEP); 382 | REPORT("[i] Time spent to create intervals %d ms\n", total_writed_intervals_creation_time); 383 | REPORT("[i] Time spent to check WXorX rule %d ms\n", total_wxorx_check_time); 384 | } 385 | REPORT("[i] Entry point 0x%08x\n", proc_info->EP); 386 | REPORT("[i] Main thread time: %d ms\n", total_time); 387 | REPORT("Size: %d Mb\n", trace_size/Mb); 388 | REPORT("Threads spawned: %d\n", spawned_threads_no); 389 | REPORT("=======================\n"); 390 | 391 | makeReport(); 392 | } 393 | 394 | char* getProgName(char** argv) { 395 | while (strcmp(*argv, "--")) { 396 | argv++; 397 | } 398 | char* prog_name = *(argv+1); 399 | char* back_slash = strrchr(prog_name, '\\'); 400 | if (back_slash) 401 | return back_slash + 1; 402 | return prog_name; 403 | } 404 | 405 | int main(int argc, char *argv[]) { 406 | /* Init PIN */ 407 | if (PIN_Init(argc, argv)) { 408 | Usage(); 409 | return 0; 410 | } 411 | 412 | /* Config the Pintool */ 413 | Config(); 414 | 415 | // Proc info structure 416 | proc_info = (proc_info_t*) malloc(sizeof(proc_info_t)); 417 | proc_info->EP = INVALID_ENTRY_POINT; 418 | 419 | /* Prepare TLS */ 420 | tls_key = PIN_CreateThreadDataKey(NULL); 421 | if (tls_key == INVALID_TLS_KEY) { 422 | ERROR("[x] Number of already allocated keys reached the MAX_CLIENT_TLS_KEYS limit\n"); 423 | PIN_ExitProcess(1); 424 | } 425 | 426 | /* Prepare Locks, Mutexes and Semaphores*/ 427 | PIN_InitLock(&pin_lock); 428 | PIN_MutexInit(&flusher_req_mutex); 429 | PIN_SemaphoreInit(&flusher_ready_sem); 430 | // Flusher 431 | PIN_SemaphoreInit(&flusher::flusher_sem); 432 | PIN_SemaphoreSet(&flusher::flusher_ready_sem); 433 | 434 | 435 | /* Spawn flusher thread if necessary */ 436 | if (isThreadFlushed) 437 | PIN_SpawnInternalThread(flusher::flusherThread, 0, 0, &flusher_uid); 438 | 439 | /* Prepare structures for online mode */ 440 | upx_dump_file = fopen("upx.dump", "w+"); 441 | upx_info = (upx_info_t*) calloc(1, sizeof(upx_info_t)); 442 | upx_info->OEP = INVALID_ENTRY_POINT; 443 | written_mem_intervals = list>(); 444 | 445 | prog_name = getProgName(argv); 446 | INS_AddInstrumentFunction(Ins, 0); 447 | IMG_AddInstrumentFunction(Img, 0); 448 | 449 | PIN_AddThreadStartFunction(ThreadStart, 0); 450 | PIN_AddThreadFiniFunction(ThreadFini, 0); 451 | 452 | PIN_AddApplicationStartFunction(ApplicationStartFunction, 0); 453 | PIN_AddPrepareForFiniFunction(PrepareForFini, 0); 454 | PIN_AddFiniFunction(Fini, 0); 455 | 456 | /*INFO("[*] trace_t size: %d\n", sizeof(trace_t)); 457 | INFO("[*] doub_buf_trace_t size: %d\n", sizeof(doub_buf_trace_t));*/ 458 | 459 | PIN_StartProgram(); 460 | return 0; 461 | } -------------------------------------------------------------------------------- /icount/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "pin.H" 4 | #include "constants.h" 5 | #include "proc.h" 6 | 7 | #define TRACE_PADDING CACHE_LINE_SIZE - 12 8 | 9 | typedef struct trace_s { 10 | size_t cursor; 11 | char* buf; 12 | uint8_t _pad[TRACE_PADDING]; 13 | size_t buf_size; 14 | } trace_t; 15 | 16 | typedef struct doub_buf_trace_s { 17 | trace_t trace; 18 | bool isFlushBufEmpty; 19 | bool isFlushing; 20 | char* flush_buf; 21 | size_t flush_buf_len; 22 | PIN_SEMAPHORE end_flush_sem; 23 | } doub_buf_trace_t; 24 | 25 | // Stats 26 | extern size_t total_flushes; 27 | 28 | #define flushTraceToFile(f, buf, buf_len) { fwrite(buf, sizeof(char), buf_len, f); fflush(f); total_flushes++; } 29 | //#define flushTraceToFile(f, buf, buf_len) { PIN_Sleep(70); total_flushes++;} 30 | 31 | #define recordTraceInMemory(buf, buf_len, trace) {\ 32 | memcpy(trace->buf + trace->cursor, buf, buf_len);\ 33 | trace->cursor += buf_len;\ 34 | trace_size += buf_len;\ 35 | } 36 | 37 | #define recordTraceToFile(f, buf, buf_len, trace) { flushTraceToFile(f, buf, buf_len); trace_size += buf_len; } 38 | 39 | bool traceLimitGuard(trace_t* trace, size_t buf_len, THREADID thread_idx); 40 | 41 | extern TLS_KEY tls_key; 42 | 43 | extern PIN_LOCK pin_lock; 44 | extern PIN_MUTEX flusher_req_mutex; 45 | extern PIN_SEMAPHORE flusher_ready_sem; 46 | extern PIN_THREAD_UID flusher_uid; 47 | 48 | // Stats 49 | extern time_t total_time; 50 | extern time_t total_sync_time; 51 | extern time_t total_wait_time; 52 | extern time_t total_flusher_time; 53 | extern time_t total_flusher_flushing_time; 54 | extern time_t total_flushing_time; 55 | extern time_t total_writed_intervals_creation_time; 56 | extern time_t total_wxorx_check_time; 57 | 58 | extern size_t spawned_threads_no; 59 | extern size_t trace_size; 60 | extern size_t total_flushes; 61 | extern proc_info_t* proc_info; 62 | extern string performance_tag; 63 | 64 | // Configs 65 | extern bool isBuffered; 66 | extern bool isThreadFlushed; 67 | extern bool isMainThreadFavored; 68 | extern size_t trace_limit; 69 | extern size_t thread_buffer_size; 70 | 71 | extern bool isFirstIns; 72 | extern const char* prog_name; 73 | 74 | extern trace_t* traces[THREADS_MAX_NO]; 75 | extern FILE* files[THREADS_MAX_NO]; 76 | extern bool hasReachedTraceLimit[THREADS_MAX_NO]; 77 | 78 | // Online 79 | extern upx_info_t* upx_info; 80 | extern bool isBinaryPacked; 81 | extern FILE* upx_dump_file; 82 | extern list> written_mem_intervals; 83 | extern pair main_img_memory; 84 | extern pair text_sec_memory; -------------------------------------------------------------------------------- /icount/offline_flushed.cpp: -------------------------------------------------------------------------------- 1 | #include "pin.H" 2 | #include 3 | #include 4 | #include "types.h" 5 | 6 | #define INS_DELIMITER '\n' 7 | #define ADDR_CHARS sizeof(ADDRINT) 8 | 9 | #define RAW_TRACE_BUF_SIZE 512*Kb 10 | #define TRACE_LIMIT 256*Mb 11 | #define TRACE_NAME_LENGTH_LIMIT 128 12 | #define THREADS_MAX_NO 256 13 | 14 | static TLS_KEY tls_key = INVALID_TLS_KEY; 15 | PIN_LOCK pin_lock; 16 | 17 | static size_t spawned_threads_no; 18 | 19 | bool isFirstIns = true; 20 | const char* prog_name; 21 | 22 | trace_t* traces[THREADS_MAX_NO]; 23 | 24 | void recordInRawTrace(const char* buf, size_t buf_len, trace_t* trace) { 25 | memcpy(trace->buf + trace->cursor, buf, buf_len); 26 | trace->cursor += buf_len; 27 | } 28 | 29 | void printRawTrace(FILE* f) { 30 | size_t trace_no = 0; 31 | trace_t* trace = traces[trace_no]; 32 | while (trace != NULL) { 33 | for (size_t i = 0; i < trace->cursor; i++) { 34 | fputc(trace->buf[i], f); 35 | } 36 | trace = traces[++trace_no]; 37 | } 38 | } 39 | 40 | void INS_Analysis(char* disassembled_ins, UINT32 disassembled_ins_len, THREADID thread_idx) { 41 | trace_t* trace = (trace_t*)PIN_GetThreadData(tls_key, thread_idx); 42 | // Trace limit guard 43 | if (trace->cursor + disassembled_ins_len >= TRACE_LIMIT) return; 44 | recordInRawTrace(disassembled_ins, disassembled_ins_len, trace); 45 | } 46 | 47 | void INS_JumpAnalysis(ADDRINT target_branch, INT32 taken, THREADID thread_idx) { 48 | if (!taken) return; 49 | trace_t* trace = (trace_t*)PIN_GetThreadData(tls_key, thread_idx); 50 | /* Allocate enough space in order to save: 51 | - @ char (1 byte) 52 | - address in hex format (sizeof(ADDRINT) * 2 bytes) + '0x' prefix (2 bytes) 53 | - \n delimiter (1 byte) 54 | - 0 terminator (1 byte) 55 | */ 56 | size_t buf_len = (sizeof(ADDRINT) * 2 + 5); 57 | // Trace limit guard 58 | if (trace->cursor + buf_len >= TRACE_LIMIT) return; 59 | char* buf = (char*)calloc(1, sizeof(char) * buf_len); 60 | buf[0] = '\n'; 61 | buf[1] = '@'; 62 | sprintf(buf + 2, "%x", target_branch); 63 | recordInRawTrace(buf, buf_len, trace); 64 | } 65 | 66 | void Trace(TRACE trace, void* v) { 67 | // Let's whitelist the instrumented program only 68 | RTN rtn = TRACE_Rtn(trace); 69 | if (RTN_Valid(rtn)) { 70 | SEC sec = RTN_Sec(rtn); 71 | if (SEC_Valid(sec)) { 72 | IMG img = SEC_Img(sec); 73 | if (IMG_Valid(img)) { 74 | if (!strstr(IMG_Name(img).c_str(), prog_name)) { 75 | //fprintf(stdout, "[-] Ignoring %s\n", IMG_Name(img).c_str()); 76 | return; 77 | } 78 | //fprintf(stdout, "[+] Instrumenting %s <= %s\n", IMG_Name(img).c_str(), prog_name); 79 | //fflush(stdout); 80 | } else return; 81 | } else return; 82 | } else return; 83 | 84 | for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { 85 | for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) { 86 | string disassembled_ins_s = INS_Disassemble(ins); 87 | /* Allocate enough space to save 88 | - Disassembled instruction (n bytes) 89 | - INS_DELIMITER (1 byte) 90 | - 0 terminator (1 byte) 91 | */ 92 | uint32_t disassembled_ins_len = strlen(disassembled_ins_s.c_str()) + 2; 93 | char* disassembled_ins = (char*)calloc(1, sizeof(char) * (disassembled_ins_len)); 94 | disassembled_ins[0] = INS_DELIMITER; 95 | strcpy(disassembled_ins + 1, disassembled_ins_s.c_str()); 96 | if (isFirstIns) { 97 | isFirstIns = false; 98 | strcpy(disassembled_ins, disassembled_ins + 1); 99 | } 100 | 101 | INS_InsertCall(ins, IPOINT_BEFORE, 102 | (AFUNPTR)INS_Analysis, 103 | IARG_PTR, 104 | disassembled_ins, 105 | IARG_UINT32, 106 | disassembled_ins_len, 107 | IARG_THREAD_ID, 108 | IARG_END); 109 | 110 | 111 | if (INS_IsBranchOrCall(ins)) { 112 | INS_InsertCall(ins, IPOINT_BEFORE, 113 | (AFUNPTR)INS_JumpAnalysis, 114 | IARG_BRANCH_TARGET_ADDR, 115 | IARG_BRANCH_TAKEN, 116 | IARG_THREAD_ID, 117 | IARG_END); 118 | } 119 | } 120 | } 121 | } 122 | 123 | void ThreadStart(THREADID thread_idx, CONTEXT* ctx, INT32 flags, VOID* v) { 124 | fprintf(stdout, "[*] Spawned thread %d\n", thread_idx); 125 | fflush(stdout); 126 | /* Initialize a raw trace per thread */ 127 | PIN_GetLock(&pin_lock, thread_idx); 128 | trace_t* trace = (trace_t*)malloc(sizeof(trace_t*)); 129 | trace->buf = (char*)malloc(sizeof(char) * RAW_TRACE_BUF_SIZE); 130 | trace->cursor = 0; 131 | traces[thread_idx] = trace; 132 | if (PIN_SetThreadData(tls_key, trace, thread_idx) == FALSE) { 133 | fprintf(stderr, "[x] PIN_SetThreadData failed"); 134 | PIN_ExitProcess(1); 135 | } 136 | spawned_threads_no++; 137 | PIN_ReleaseLock(&pin_lock); 138 | 139 | } 140 | 141 | void ThreadFini(THREADID thread_idx, const CONTEXT* ctx, INT32 code, VOID* v) { 142 | fprintf(stdout, "[*] Finished thread %d\n", thread_idx); 143 | fflush(stdout); 144 | char filename[TRACE_NAME_LENGTH_LIMIT] = { 0 }; 145 | sprintf(filename, "trace_%d.out", thread_idx); 146 | FILE* out = fopen(filename, "w+"); 147 | printRawTrace(out); 148 | fprintf(stdout, "[+] Trace for thread #%d saved to %s\n", thread_idx, filename); 149 | } 150 | 151 | void Fini(INT32 code, VOID *v) { 152 | fprintf(stdout, "=======================\n"); 153 | fprintf(stdout, "Trace finished\n"); 154 | //fprintf(stdout, "Size: %d Kb\n", raw_trace->trace_size / (1024)); 155 | fprintf(stdout, "Threads spawned: %d\n", spawned_threads_no); 156 | fprintf(stdout, "=======================\n"); 157 | } 158 | 159 | int main(int argc, char *argv[]) { 160 | /* Init PIN */ 161 | if (PIN_Init(argc, argv)) { 162 | fprintf(stderr, "[x] An error occured while initiating PIN\n"); 163 | return 0; 164 | } 165 | 166 | /* Prepare TLS */ 167 | tls_key = PIN_CreateThreadDataKey(NULL); 168 | if (tls_key == INVALID_TLS_KEY) { 169 | fprintf(stderr, "[x] Number of already allocated keys reached the MAX_CLIENT_TLS_KEYS limit\n"); 170 | PIN_ExitProcess(1); 171 | } 172 | 173 | /* Prepare Lock */ 174 | PIN_InitLock(&pin_lock); 175 | 176 | prog_name = argv[argc - 1]; 177 | TRACE_AddInstrumentFunction(Trace, 0); 178 | 179 | PIN_AddThreadStartFunction(ThreadStart, 0); 180 | PIN_AddThreadFiniFunction(ThreadFini, 0); 181 | 182 | PIN_AddFiniFunction(Fini, 0); 183 | PIN_StartProgram(); 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /icount/proc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct proc_info_s { 4 | ADDRINT EP; 5 | } proc_info_t; 6 | 7 | typedef struct upx_info_s { 8 | bool metPushad; 9 | bool metPopad; 10 | bool metJmp; 11 | ADDRINT OEP; 12 | } upx_info_t; -------------------------------------------------------------------------------- /icount/report.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "report.h" 3 | 4 | #include "json.h" 5 | #include "main.h" 6 | #include "constants.h" 7 | 8 | std::ofstream ReportFile; 9 | std::ofstream PerformanceFile; 10 | 11 | Json::Value report_j; 12 | Json::Value performance_j; 13 | 14 | void reportImage(IMG img) { 15 | string img_name = IMG_Name(img); 16 | ADDRINT low_address = IMG_LowAddress(img); 17 | ADDRINT high_address = IMG_HighAddress(img); 18 | report_j["images"][img_name]["low_address"] = low_address; 19 | report_j["images"][img_name]["high_address"] = high_address; 20 | } 21 | 22 | void reportMainImage(IMG img) { 23 | string img_name = IMG_Name(img); 24 | report_j["main_image"] = img_name; 25 | } 26 | 27 | void makeReport() { 28 | if (isBinaryPacked) { 29 | // TODO: This has to be found dinamically 30 | report_j["text_section"] = "UPX0"; 31 | report_j["entry_point"] = upx_info->OEP; 32 | } else { 33 | report_j["text_section"] = TEXT_SEC_NAME; 34 | report_j["entry_point"] = proc_info->EP; 35 | } 36 | 37 | if (performance_tag != "") { 38 | if (isThreadFlushed) { 39 | performance_j["mode"] = "thread_flushed"; 40 | performance_j["sync_with_flusher"] = total_sync_time; 41 | performance_j["waiting_for_flusher"] = total_wait_time; 42 | performance_j["flusher_flushing"] = total_flusher_flushing_time; 43 | performance_j["flusher_running"] = total_flusher_time; 44 | performance_j["average_flush_time"] = (int) (total_flusher_flushing_time / total_flushes); 45 | } else if (isBuffered) { 46 | performance_j["mode"] = "buffered"; 47 | performance_j["flushing_time"] = total_flushing_time; 48 | performance_j["average_flush_time"] = (int) (total_flushing_time / total_flushes); 49 | } else { 50 | performance_j["mode"] = "flushed"; 51 | } 52 | performance_j["main_thread_time"] = total_time; 53 | performance_j["trace_size"] = trace_size / Mb; 54 | 55 | PerformanceFile.open(performance_tag.c_str()); 56 | PerformanceFile << performance_j; 57 | } 58 | 59 | ReportFile.open("report.json"); 60 | ReportFile << report_j; 61 | } -------------------------------------------------------------------------------- /icount/report.h: -------------------------------------------------------------------------------- 1 | #include "json.h" 2 | #include "pin.H" 3 | 4 | void reportImage(IMG img); 5 | void reportMainImage(IMG img); 6 | void makeReport(); 7 | 8 | extern Json::Value report_j; -------------------------------------------------------------------------------- /icount/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | /* Time utils */ 5 | #define START_STOPWATCH(tv) { tv = clock(); } 6 | #define GET_STOPWATCH_LAP(tv) clock() - tv 7 | 8 | /* Math utils */ 9 | #define IN_RANGE(a, b, c) (a >= b && a <= c) -------------------------------------------------------------------------------- /performance_parser.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | reports = {} 5 | for report_file_name in filter(lambda f: '.report' in f, os.listdir()): 6 | with open(report_file_name) as report_file: 7 | perf_report = json.load(report_file) 8 | mode_name = perf_report['mode'] 9 | if mode_name not in reports: 10 | reports[mode_name] = {} 11 | reports[mode_name]['count'] = 0 12 | reports[mode_name]['count'] += 1 13 | 14 | for stat, value in perf_report.items(): 15 | if stat == 'mode': 16 | continue 17 | if stat not in reports[mode_name]: 18 | reports[mode_name][stat] = 0 19 | reports[mode_name][stat] += value 20 | 21 | for mode, stats in reports.items(): 22 | count = stats['count'] 23 | for stat, value in stats.items(): 24 | if stat == 'mode' or stat == 'count': 25 | continue 26 | reports[mode][stat] = value/count 27 | 28 | print(reports) -------------------------------------------------------------------------------- /pintools.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "icount", "icount\MyPinTool.vcxproj", "{639EF517-FCFC-408E-9500-71F0DC0458DB}" 7 | EndProject 8 | Global 9 | GlobalSection(Performance) = preSolution 10 | HasPerformanceSessions = true 11 | EndGlobalSection 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Win32 = Debug|Win32 14 | Debug|x64 = Debug|x64 15 | Release|Win32 = Release|Win32 16 | Release|x64 = Release|x64 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Debug|Win32.ActiveCfg = Debug|Win32 20 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Debug|Win32.Build.0 = Debug|Win32 21 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Debug|x64.ActiveCfg = Debug|x64 22 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Debug|x64.Build.0 = Debug|x64 23 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Release|Win32.ActiveCfg = Release|x64 24 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Release|x64.ActiveCfg = Debug|Win32 25 | {639EF517-FCFC-408E-9500-71F0DC0458DB}.Release|x64.Build.0 = Debug|Win32 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | GlobalSection(ExtensibilityGlobals) = postSolution 31 | SolutionGuid = {E492018D-DFDB-4968-97A1-6BC02CEF7740} 32 | EndGlobalSection 33 | EndGlobal 34 | -------------------------------------------------------------------------------- /tester.ps1: -------------------------------------------------------------------------------- 1 | $TESTS_NUM = 3 2 | $TRACE_LIMIT = 4090 3 | 4 | function clear_env() { 5 | Invoke-Expression "rm trace*" 6 | } 7 | 8 | function clear_reports() { 9 | Invoke-Expression "rm *.report" 10 | } 11 | 12 | function runTests ($tag, $base, $arguments) { 13 | # $highest = -1; 14 | # $lowest = 999999; 15 | $totalMillisecondsSum = 0 16 | for ($i = 0; $i -lt $TESTS_NUM; $i++) { 17 | clear_env 18 | Write-Host "[($i) $tag]" 19 | $report_tag = "$(Get-Date -Format FileDateTime)" + ".report" 20 | $time_span = Measure-Command { Invoke-Expression "$base -trace_limit $TRACE_LIMIT -tag $report_tag $arguments" | Out-Default } 21 | $totalMilliseconds = $time_span.TotalMilliseconds 22 | $totalMillisecondsSum += $totalMilliseconds 23 | # if ($totalMilliseconds -gt $highest) { $highest = $totalMilliseconds } 24 | # if ($totalMilliseconds -lt $lowest) { $lowest = $totalMilliseconds } 25 | } 26 | # $totalMillisecondsSum -= ($highest + $lowest) 27 | # $avg_time = $totalMillisecondsSum / ($TESTS_NUM - 2) 28 | $avg_time = ($totalMillisecondsSum / $TESTS_NUM) 29 | Write-Host "{$tag Average time: $avg_time}" 30 | } 31 | 32 | # $PROG = "C:\Users\tulim\Downloads\fciv.exe -md5 -sha1 C:\Users\tulim\Downloads\ubuntu-17.10-desktop-amd64.iso" 33 | # $PROG = "C:\Users\tulim\Downloads\fciv.vmp.exe C:\Users\tulim\Downloads\ubuntu-17.10-desktop-amd64.iso" 34 | # $PROG = "driverquery /V" 35 | # $PROG = "systeminfo" 36 | $BASE = "C:\Pin35\pin.exe -t C:\Pin35\icount32.dll -trace_limit $TRACE_LIMIT" 37 | clear_reports 38 | Write-Host "--- Beginning Tests for --- $PROG" 39 | 40 | $XS_THREAD_BUF = 10 41 | $SM_THREAD_BUF = 30 42 | $MD_THREAD_BUF = 50 43 | $LG_THREAD_BUF = 100 44 | $XL_THREAD_BUF = 200 45 | 46 | # runTests "Original" $PROG "--" 47 | 48 | # runTests "Buffered ($SM_THREAD_BUF Mb)" $BASE "-buffered -thread_buffer_size $SM_THREAD_BUF -- $PROG" 49 | 50 | # runTests "Thread flushed ($SM_THREAD_BUF Mb)" $BASE "-thread_flushed -thread_buffer_size $SM_THREAD_BUF -- $PROG" 51 | 52 | runTests "Flushed" $BASE "-- $PROG" --------------------------------------------------------------------------------