-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzerospy_client_fast.cpp
1881 lines (1727 loc) · 74.8 KB
/
zerospy_client_fast.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
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
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// @COPYRIGHT@
// Licensed under MIT license.
// See LICENSE.TXT file in the project root for more information.
// ==============================================================
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <malloc.h>
#include <iostream>
#include <unistd.h>
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
#include <string.h>
#include <sys/mman.h>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <list>
#include "pin.H"
#include "cctlib.H"
// #include "shadow_memory.H"
#include <xmmintrin.h>
#include <immintrin.h>
// definition of BYTE_ORDER
#include <endian.h>
extern "C" {
#include "xed-interface.h"
#include "xed-common-hdrs.h"
}
// #include <google/sparse_hash_map>
// #include <google/dense_hash_map>
// using google::sparse_hash_map; // namespace where class lives by default
// using google::dense_hash_map;
using namespace std;
using namespace PinCCTLib;
// have R, W representative macros
#define READ_ACTION (0)
#define WRITE_ACTION (0xff)
#define ONE_BYTE_READ_ACTION (0)
#define TWO_BYTE_READ_ACTION (0)
#define FOUR_BYTE_READ_ACTION (0)
#define EIGHT_BYTE_READ_ACTION (0)
#define ONE_BYTE_WRITE_ACTION (0xff)
#define TWO_BYTE_WRITE_ACTION (0xffff)
#define FOUR_BYTE_WRITE_ACTION (0xffffffff)
#define EIGHT_BYTE_WRITE_ACTION (0xffffffffffffffff)
#define IS_ACCESS_WITHIN_PAGE_BOUNDARY(accessAddr, accessLen) (PAGE_OFFSET((accessAddr)) <= (PAGE_OFFSET_MASK - (accessLen)))
/* Other footprint_client settings */
#define MAX_REDUNDANT_CONTEXTS_TO_LOG (1000)
#define THREAD_MAX (1024)
#define ENCODE_ADDRESS_AND_ACCESS_LEN(addr, len) ( (addr) | (((uint64_t)(len)) << 48))
#define DECODE_ADDRESS(addrAndLen) ( (addrAndLen) & ((1L<<48) - 1))
#define DECODE_ACCESS_LEN(addrAndLen) ( (addrAndLen) >> 48)
#define MAX_WRITE_OP_LENGTH (512)
#define MAX_WRITE_OPS_IN_INS (8)
#define MAX_REG_LENGTH (64)
#define MAX_SIMD_LENGTH (64)
#define MAX_SIMD_REGS (32)
#define PAGE_MASK (~0xfff)
#define GET_PAGE_INDEX(x) ((x) & PAGE_MASK)
#define CACHELINE_MASK (~63)
#define GET_CACHELINE_INDEX(x) ((x) & CACHELINE_MASK)
//#define MERGING
// #define NO_APPROXMAP
// #define SKIP_SMALLCASE
#ifdef ENABLE_SAMPLING
#define WINDOW_ENABLE 1000000
#define WINDOW_DISABLE 100000000
#define WINDOW_CLEAN 10
#endif
#define DECODE_DEAD(data) static_cast<uint8_t>(((data) & 0xffffffffffffffff) >> 32 )
#define DECODE_KILL(data) (static_cast<ContextHandle_t>( (data) & 0x00000000ffffffff))
#define MAKE_CONTEXT_PAIR(a, b) (((uint64_t)(a) << 32) | ((uint64_t)(b)))
#define delta 0.01
// #define ENABLE_FILTER_BEFORE_SORT
#define MULTI_THREADED
#ifdef NO_CRT
KNOB<BOOL> KnobFlatProfile(KNOB_MODE_WRITEONCE, "pintool", "fp", "0", "Collect flat profile");
#endif
#define static_assert(x) static_assert(x,#x)
/***********************************************
****** shadow memory
************************************************/
//ConcurrentShadowMemory<uint8_t, ContextHandle_t> sm;
struct{
char dummy1[128];
xed_state_t xedState;
char dummy2[128];
} LoadSpyGlobals;
struct RedSpyThreadData{
uint64_t bytesLoad;
};
// for metric logging
int redload_metric_id = 0;
int redload_approx_metric_id = 0;
//for statistics result
uint64_t grandTotBytesLoad;
uint64_t grandTotBytesRedLoad;
uint64_t grandTotBytesApproxRedLoad;
// 64 byte per cacheline : 8 * int64
struct __attribute__((aligned(64))) CachelineAlignedInt64_t {
uint64_t val;
};
CachelineAlignedInt64_t threadBytesLoad[THREAD_MAX] __attribute__((aligned(64)));
//uint64_t localTotBytesLoad[THREAD_MAX] = {0};
// key for accessing TLS storage in the threads. initialized once in main()
static TLS_KEY client_tls_key;
static RedSpyThreadData* gSingleThreadedTData;
// function to access thread-specific data
inline RedSpyThreadData* ClientGetTLS(const THREADID threadId) {
#ifdef MULTI_THREADED
RedSpyThreadData* tdata =
static_cast<RedSpyThreadData*>(PIN_GetThreadData(client_tls_key, threadId));
return tdata;
#else
return gSingleThreadedTData;
#endif
}
static INT32 Usage() {
PIN_ERROR("Pin tool to gather calling context on each load and store.\n" + KNOB_BASE::StringKnobSummary() + "\n");
return -1;
}
// Main for RedSpy, initialize the tool, register instrumentation functions and call the target program.
static FILE* gTraceFile;
//#define DEBUG_ZEROSPY
#ifdef DEBUG_ZEROSPY
static FILE* gDebugFile[200]={0};
static FILE* getDebugFile(int i) {
if(!gDebugFile[i]) {
char filename[20];
sprintf(filename, "debug.%d.txt",i);
gDebugFile[i] = fopen(filename,"w");
}
return gDebugFile[i];
}
#endif
// Initialized the needed data structures before launching the target program
static void ClientInit(int argc, char* argv[]) {
// Create output file
char name[MAX_FILE_PATH] = "zeroLoad.out.";
char* envPath = getenv("CCTLIB_CLIENT_OUTPUT_FILE");
if(envPath) {
// assumes max of MAX_FILE_PATH
strcpy(name, envPath);
}
gethostname(name + strlen(name), MAX_FILE_PATH - strlen(name));
pid_t pid = getpid();
sprintf(name + strlen(name), "%d", pid);
cerr << "\n Creating log file at:" << name << "\n";
gTraceFile = fopen(name, "w");
// print the arguments passed
fprintf(gTraceFile, "\n");
for(int i = 0 ; i < argc; i++) {
fprintf(gTraceFile, "%s ", argv[i]);
}
fprintf(gTraceFile, "\n");
// Init Xed
// Init XED for decoding instructions
xed_state_init(&LoadSpyGlobals.xedState, XED_MACHINE_MODE_LONG_64, (xed_address_width_enum_t) 0, XED_ADDRESS_WIDTH_64b);
}
static const uint64_t READ_ACCESS_STATES [] = {/*0 byte */0, /*1 byte */ ONE_BYTE_READ_ACTION, /*2 byte */ TWO_BYTE_READ_ACTION, /*3 byte */ 0, /*4 byte */ FOUR_BYTE_READ_ACTION, /*5 byte */0, /*6 byte */0, /*7 byte */0, /*8 byte */ EIGHT_BYTE_READ_ACTION};
static const uint64_t WRITE_ACCESS_STATES [] = {/*0 byte */0, /*1 byte */ ONE_BYTE_WRITE_ACTION, /*2 byte */ TWO_BYTE_WRITE_ACTION, /*3 byte */ 0, /*4 byte */ FOUR_BYTE_WRITE_ACTION, /*5 byte */0, /*6 byte */0, /*7 byte */0, /*8 byte */ EIGHT_BYTE_WRITE_ACTION};
static const uint8_t OVERFLOW_CHECK [] = {/*0 byte */0, /*1 byte */ 0, /*2 byte */ 0, /*3 byte */ 1, /*4 byte */ 2, /*5 byte */3, /*6 byte */4, /*7 byte */5, /*8 byte */ 6};
struct RedLogs{
uint64_t tot;
uint64_t red;
uint64_t fred; // full redundancy
uint64_t redByteMap;
};
struct ApproxRedLogs{
uint64_t fred; // full redundancy
uint64_t ftot;
uint64_t redByteMap;
uint8_t AccessLen;
uint8_t size;
};
//static unordered_map<uint64_t, uint64_t> validMap[THREAD_MAX];
static unordered_map<uint64_t, RedLogs> RedMap[THREAD_MAX];
static unordered_map<uint64_t, ApproxRedLogs> ApproxRedMap[THREAD_MAX];
static inline void AddToRedTable(uint64_t key, uint16_t value, uint64_t byteMap, uint16_t total, THREADID threadId) __attribute__((always_inline,flatten));
static inline void AddToRedTable(uint64_t key, uint16_t value, uint64_t byteMap, uint16_t total, THREADID threadId) {
unordered_map<uint64_t, RedLogs>::iterator it = RedMap[threadId].find(key);
if ( it == RedMap[threadId].end()) {
RedLogs log;
log.red = value;
log.tot = total;
log.fred= (value==total);
log.redByteMap = byteMap;
//if(total < value) cerr << "ERROR : total " << total << " < value " << value << endl;
RedMap[threadId][key] = log;
//printf("Bucket size : %ld\n",RedMap[threadId].bucket_count());
} else {
it->second.red += value;
it->second.tot += total;
it->second.fred+= (value==total);
it->second.redByteMap &= byteMap;
//if(total < value) cerr << "ERROR : total " << total << " < value " << value << endl;
//assert(it->second.AccessLen == total && "AccessLen not match");
}
}
static inline void AddToApproximateRedTable(uint64_t key, uint64_t byteMap, uint16_t total, uint16_t zeros, uint16_t nums, uint8_t size, THREADID threadId) __attribute__((always_inline,flatten));
static inline void AddToApproximateRedTable(uint64_t key, uint64_t byteMap, uint16_t total, uint16_t zeros, uint16_t nums, uint8_t size, THREADID threadId) {
unordered_map<uint64_t, ApproxRedLogs>::iterator it = ApproxRedMap[threadId].find(key);
if ( it == ApproxRedMap[threadId].end()) {
ApproxRedLogs log;
log.fred= zeros;
log.ftot= nums;
log.redByteMap = byteMap;
log.AccessLen = total;
log.size = size;
//if(total < value) cerr << "ERROR : total " << total << " < value " << value << endl;
ApproxRedMap[threadId][key] = log;
} else {
it->second.fred+= zeros;
it->second.ftot+= nums;
it->second.redByteMap &= byteMap;
//if(total < value) cerr << "ERROR : total " << total << " < value " << value << endl;
//assert(it->second.AccessLen == total && "AccessLen not match");
}
}
#ifdef ENABLE_SAMPLING
static ADDRINT IfEnableSample(THREADID threadId){
RedSpyThreadData* const tData = ClientGetTLS(threadId);
return tData->sampleFlag;
}
#endif
// Certain FP instructions should not be approximated
static inline bool IsOkToApproximate(xed_decoded_inst_t & xedd) {
xed_category_enum_t cat = xed_decoded_inst_get_category(&xedd);
xed_iclass_enum_t iclass = xed_decoded_inst_get_iclass (&xedd);
switch(iclass) {
case XED_ICLASS_FLDENV:
case XED_ICLASS_FNSTENV:
case XED_ICLASS_FNSAVE:
case XED_ICLASS_FLDCW:
case XED_ICLASS_FNSTCW:
case XED_ICLASS_FNSTSW:
case XED_ICLASS_FXRSTOR:
case XED_ICLASS_FXRSTOR64:
case XED_ICLASS_FXSAVE:
case XED_ICLASS_FXSAVE64:
return false;
default:
return true;
}
}
static inline bool IsFloatInstructionAndOkToApproximate(ADDRINT ip) {
#ifdef DEBUG_ZEROSPY
FILE* debug = getDebugFile(0);
#endif
xed_decoded_inst_t xedd;
xed_decoded_inst_zero_set_mode(&xedd, &LoadSpyGlobals.xedState);
if(XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
xed_category_enum_t cat = xed_decoded_inst_get_category(&xedd);
#ifdef DEBUG_ZEROSPY
char xxx[200] = {0};
xed_decoded_inst_dump (&xedd, xxx, 200);
xed_format_context(XED_SYNTAX_ATT, &xedd, xxx, 200, ip, 0, 0);
fprintf(debug, " IP = %lx %s\n", ip, xxx);
#endif
switch (cat) {
case XED_CATEGORY_AES:
case XED_CATEGORY_CONVERT:
case XED_CATEGORY_PCLMULQDQ:
case XED_CATEGORY_SSE:
case XED_CATEGORY_AVX2:
case XED_CATEGORY_AVX:
case XED_CATEGORY_MMX:
case XED_CATEGORY_DATAXFER: {
// Get the mem operand
const xed_inst_t* xi = xed_decoded_inst_inst(&xedd);
int noperands = xed_inst_noperands(xi);
int memOpIdx = -1;
for( int i =0; i < noperands ; i++) {
const xed_operand_t* op = xed_inst_operand(xi,i);
xed_operand_enum_t op_name = xed_operand_name(op);
if(XED_OPERAND_MEM0 == op_name) {
memOpIdx = i;
break;
}
}
if(memOpIdx == -1) {
return false;
}
// TO DO MILIND case XED_OPERAND_MEM1:
xed_operand_element_type_enum_t eType = xed_decoded_inst_operand_element_type(&xedd,memOpIdx);
switch (eType) {
case XED_OPERAND_ELEMENT_TYPE_FLOAT16:
case XED_OPERAND_ELEMENT_TYPE_SINGLE:
case XED_OPERAND_ELEMENT_TYPE_DOUBLE:
case XED_OPERAND_ELEMENT_TYPE_LONGDOUBLE:
case XED_OPERAND_ELEMENT_TYPE_LONGBCD:
return IsOkToApproximate(xedd);
default:
return false;
}
}
break;
case XED_CATEGORY_X87_ALU:
case XED_CATEGORY_FCMOV:
//case XED_CATEGORY_LOGICAL_FP:
// assumption, the access length must be either 4 or 8 bytes else assert!!!
//assert(*accessLen == 4 || *accessLen == 8);
return IsOkToApproximate(xedd);
case XED_CATEGORY_XSAVE:
case XED_CATEGORY_AVX2GATHER:
case XED_CATEGORY_STRINGOP:
default: return false;
}
}else {
assert(0 && "failed to disassemble instruction");
// printf("\n Diassembly failure\n");
return false;
}
}
static inline bool IsFloatInstructionOld(ADDRINT ip) {
xed_decoded_inst_t xedd;
xed_decoded_inst_zero_set_mode(&xedd, &LoadSpyGlobals.xedState);
if(XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
xed_iclass_enum_t iclassType = xed_decoded_inst_get_iclass(&xedd);
if (iclassType >= XED_ICLASS_F2XM1 && iclassType <=XED_ICLASS_FYL2XP1) {
return true;
}
if (iclassType >= XED_ICLASS_VBROADCASTSD && iclassType <= XED_ICLASS_VDPPS) {
return true;
}
if (iclassType >= XED_ICLASS_VRCPPS && iclassType <= XED_ICLASS_VSQRTSS) {
return true;
}
if (iclassType >= XED_ICLASS_VSUBPD && iclassType <= XED_ICLASS_VXORPS) {
return true;
}
switch (iclassType) {
case XED_ICLASS_ADDPD:
case XED_ICLASS_ADDPS:
case XED_ICLASS_ADDSD:
case XED_ICLASS_ADDSS:
case XED_ICLASS_ADDSUBPD:
case XED_ICLASS_ADDSUBPS:
case XED_ICLASS_ANDNPD:
case XED_ICLASS_ANDNPS:
case XED_ICLASS_ANDPD:
case XED_ICLASS_ANDPS:
case XED_ICLASS_BLENDPD:
case XED_ICLASS_BLENDPS:
case XED_ICLASS_BLENDVPD:
case XED_ICLASS_BLENDVPS:
case XED_ICLASS_CMPPD:
case XED_ICLASS_CMPPS:
case XED_ICLASS_CMPSD:
case XED_ICLASS_CMPSD_XMM:
case XED_ICLASS_COMISD:
case XED_ICLASS_COMISS:
case XED_ICLASS_CVTDQ2PD:
case XED_ICLASS_CVTDQ2PS:
case XED_ICLASS_CVTPD2PS:
case XED_ICLASS_CVTPI2PD:
case XED_ICLASS_CVTPI2PS:
case XED_ICLASS_CVTPS2PD:
case XED_ICLASS_CVTSD2SS:
case XED_ICLASS_CVTSI2SD:
case XED_ICLASS_CVTSI2SS:
case XED_ICLASS_CVTSS2SD:
case XED_ICLASS_DIVPD:
case XED_ICLASS_DIVPS:
case XED_ICLASS_DIVSD:
case XED_ICLASS_DIVSS:
case XED_ICLASS_DPPD:
case XED_ICLASS_DPPS:
case XED_ICLASS_HADDPD:
case XED_ICLASS_HADDPS:
case XED_ICLASS_HSUBPD:
case XED_ICLASS_HSUBPS:
case XED_ICLASS_MAXPD:
case XED_ICLASS_MAXPS:
case XED_ICLASS_MAXSD:
case XED_ICLASS_MAXSS:
case XED_ICLASS_MINPD:
case XED_ICLASS_MINPS:
case XED_ICLASS_MINSD:
case XED_ICLASS_MINSS:
case XED_ICLASS_MOVAPD:
case XED_ICLASS_MOVAPS:
case XED_ICLASS_MOVD:
case XED_ICLASS_MOVHLPS:
case XED_ICLASS_MOVHPD:
case XED_ICLASS_MOVHPS:
case XED_ICLASS_MOVLHPS:
case XED_ICLASS_MOVLPD:
case XED_ICLASS_MOVLPS:
case XED_ICLASS_MOVMSKPD:
case XED_ICLASS_MOVMSKPS:
case XED_ICLASS_MOVNTPD:
case XED_ICLASS_MOVNTPS:
case XED_ICLASS_MOVNTSD:
case XED_ICLASS_MOVNTSS:
case XED_ICLASS_MOVSD:
case XED_ICLASS_MOVSD_XMM:
case XED_ICLASS_MOVSS:
case XED_ICLASS_MULPD:
case XED_ICLASS_MULPS:
case XED_ICLASS_MULSD:
case XED_ICLASS_MULSS:
case XED_ICLASS_ORPD:
case XED_ICLASS_ORPS:
case XED_ICLASS_ROUNDPD:
case XED_ICLASS_ROUNDPS:
case XED_ICLASS_ROUNDSD:
case XED_ICLASS_ROUNDSS:
case XED_ICLASS_SHUFPD:
case XED_ICLASS_SHUFPS:
case XED_ICLASS_SQRTPD:
case XED_ICLASS_SQRTPS:
case XED_ICLASS_SQRTSD:
case XED_ICLASS_SQRTSS:
case XED_ICLASS_SUBPD:
case XED_ICLASS_SUBPS:
case XED_ICLASS_SUBSD:
case XED_ICLASS_SUBSS:
case XED_ICLASS_VADDPD:
case XED_ICLASS_VADDPS:
case XED_ICLASS_VADDSD:
case XED_ICLASS_VADDSS:
case XED_ICLASS_VADDSUBPD:
case XED_ICLASS_VADDSUBPS:
case XED_ICLASS_VANDNPD:
case XED_ICLASS_VANDNPS:
case XED_ICLASS_VANDPD:
case XED_ICLASS_VANDPS:
case XED_ICLASS_VBLENDPD:
case XED_ICLASS_VBLENDPS:
case XED_ICLASS_VBLENDVPD:
case XED_ICLASS_VBLENDVPS:
case XED_ICLASS_VBROADCASTSD:
case XED_ICLASS_VBROADCASTSS:
case XED_ICLASS_VCMPPD:
case XED_ICLASS_VCMPPS:
case XED_ICLASS_VCMPSD:
case XED_ICLASS_VCMPSS:
case XED_ICLASS_VCOMISD:
case XED_ICLASS_VCOMISS:
case XED_ICLASS_VCVTDQ2PD:
case XED_ICLASS_VCVTDQ2PS:
case XED_ICLASS_VCVTPD2PS:
case XED_ICLASS_VCVTPH2PS:
case XED_ICLASS_VCVTPS2PD:
case XED_ICLASS_VCVTSD2SS:
case XED_ICLASS_VCVTSI2SD:
case XED_ICLASS_VCVTSI2SS:
case XED_ICLASS_VCVTSS2SD:
case XED_ICLASS_VDIVPD:
case XED_ICLASS_VDIVPS:
case XED_ICLASS_VDIVSD:
case XED_ICLASS_VDIVSS:
case XED_ICLASS_VDPPD:
case XED_ICLASS_VDPPS:
case XED_ICLASS_VMASKMOVPD:
case XED_ICLASS_VMASKMOVPS:
case XED_ICLASS_VMAXPD:
case XED_ICLASS_VMAXPS:
case XED_ICLASS_VMAXSD:
case XED_ICLASS_VMAXSS:
case XED_ICLASS_VMINPD:
case XED_ICLASS_VMINPS:
case XED_ICLASS_VMINSD:
case XED_ICLASS_VMINSS:
case XED_ICLASS_VMOVAPD:
case XED_ICLASS_VMOVAPS:
case XED_ICLASS_VMOVD:
case XED_ICLASS_VMOVHLPS:
case XED_ICLASS_VMOVHPD:
case XED_ICLASS_VMOVHPS:
case XED_ICLASS_VMOVLHPS:
case XED_ICLASS_VMOVLPD:
case XED_ICLASS_VMOVLPS:
case XED_ICLASS_VMOVMSKPD:
case XED_ICLASS_VMOVMSKPS:
case XED_ICLASS_VMOVNTPD:
case XED_ICLASS_VMOVNTPS:
case XED_ICLASS_VMOVSD:
case XED_ICLASS_VMOVSS:
case XED_ICLASS_VMOVUPD:
case XED_ICLASS_VMOVUPS:
case XED_ICLASS_VMULPD:
case XED_ICLASS_VMULPS:
case XED_ICLASS_VMULSD:
case XED_ICLASS_VMULSS:
case XED_ICLASS_VORPD:
case XED_ICLASS_VORPS:
case XED_ICLASS_VPABSD:
case XED_ICLASS_VPADDD:
case XED_ICLASS_VPCOMD:
case XED_ICLASS_VPCOMUD:
case XED_ICLASS_VPERMILPD:
case XED_ICLASS_VPERMILPS:
case XED_ICLASS_VPERMPD:
case XED_ICLASS_VPERMPS:
case XED_ICLASS_VPGATHERDD:
case XED_ICLASS_VPGATHERQD:
case XED_ICLASS_VPHADDBD:
case XED_ICLASS_VPHADDD:
case XED_ICLASS_VPHADDUBD:
case XED_ICLASS_VPHADDUWD:
case XED_ICLASS_VPHADDWD:
case XED_ICLASS_VPHSUBD:
case XED_ICLASS_VPHSUBWD:
case XED_ICLASS_VPINSRD:
case XED_ICLASS_VPMACSDD:
case XED_ICLASS_VPMACSSDD:
case XED_ICLASS_VPMASKMOVD:
case XED_ICLASS_VPMAXSD:
case XED_ICLASS_VPMAXUD:
case XED_ICLASS_VPMINSD:
case XED_ICLASS_VPMINUD:
case XED_ICLASS_VPROTD:
case XED_ICLASS_VPSUBD:
case XED_ICLASS_XORPD:
case XED_ICLASS_XORPS:
return true;
default: return false;
}
} else {
assert(0 && "failed to disassemble instruction");
return false;
}
}
static inline uint16_t FloatOperandSize(ADDRINT ip, uint32_t oper) {
xed_decoded_inst_t xedd;
xed_decoded_inst_zero_set_mode(&xedd, &LoadSpyGlobals.xedState);
if(XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
xed_operand_element_type_enum_t TypeOperand = xed_decoded_inst_operand_element_type(&xedd,oper);
if(TypeOperand == XED_OPERAND_ELEMENT_TYPE_SINGLE || TypeOperand == XED_OPERAND_ELEMENT_TYPE_FLOAT16)
return 4;
if (TypeOperand == XED_OPERAND_ELEMENT_TYPE_DOUBLE) {
return 8;
}
if (TypeOperand == XED_OPERAND_ELEMENT_TYPE_LONGDOUBLE) {
return 16;
}
assert(0 && "float instruction with unknown operand\n");
return 0;
} else {
assert(0 && "failed to disassemble instruction\n");
return 0;
}
}
/*******************************************************************************************/
// single floating point zero byte counter
// 32-bit float: |sign|exp|mantissa| = | 1 | 8 | 23 |
// the redmap of single floating point takes up 5 bits (1 bit sign, 1 bit exp, 3 bit mantissa)
#define SP_MAP_SIZE 5
inline __attribute__((always_inline)) uint64_t count_zero_bytemap_fp(void * addr) {
register uint32_t xx = *((uint32_t*)addr);
// reduce by bits until byte level
// | 0 | x0x0 x0x0 | 0x0 x0x0 x0x0 x0x0 x0x0 x0x0 |
xx = xx | ((xx>>1)&0xffbfffff);
// | x | 00xx 00xx | 0xx 00xx 00xx 00xx 00xx 00xx |
xx = xx | ((xx>>2)&0xffdfffff);
// | x | 0000 xxxx | 000 xxxx 0000 xxxx 0000 xxxx |
xx = xx | ((xx>>4)&0xfff7ffff);
// now xx is byte level reduced, check if it is zero and mask the unused bits
xx = (~xx) & 0x80810101;
// narrowing
xx = xx | (xx>>7) | (xx>>14) | (xx>>20) | (xx>>27);
xx = xx & 0x1f;
return xx;
}
inline __attribute__((always_inline)) bool hasRedundancy_fp(void * addr) {
register uint32_t xx = *((uint32_t*)addr);
return (xx & 0x007f0000)==0;
}
/*******************************************************************************************/
// double floating point zero byte counter
// 64-bit float: |sign|exp|mantissa| = | 1 | 11 | 52 |
// the redmap of single floating point takes up 10 bits (1 bit sign, 2 bit exp, 7 bit mantissa)
#define DP_MAP_SIZE 10
inline __attribute__((always_inline)) uint64_t count_zero_bytemap_dp(void * addr) {
register uint64_t xx = (static_cast<uint64_t*>(addr))[0];
// reduce by bits until byte level
// | 0 | 0x0 x0x0 x0x0 | x0x0 x0x0_x0x0 x0x0_x0x0 x0x0_x0x0 x0x0_x0x0 x0x0_x0x0 x0x0_x0x0 |
xx = xx | ((xx>>1)&(~0x4008000000000000LL));
// | x | 0xx 00xx 00xx | 00xx 00xx_00xx 00xx_00xx 00xx_00xx 00xx_00xx 00xx_00xx 00xx_00xx |
xx = xx | ((xx>>2)&(~0x200c000000000000LL));
// | x | xxx 0000 xxxx | xxxx 0000_xxxx 0000_xxxx 0000_xxxx 0000_xxxx 0000_xxxx 0000_xxxx |
xx = xx | ((xx>>4)&(~0x100f000000000000LL));
// now xx is byte level reduced, check if it is zero and mask the unused bits
xx = (~xx) & 0x9011010101010101LL;
// narrowing
register uint64_t m = xx & 0x1010101010101LL;
m = m | (m>>7);
m = m | (m>>14);
m = m | (m>>28);
m = m & 0x7f;
xx = xx | (xx>>9) | (xx>>7);
xx = (xx >> 45) & 0x380;
xx = m | xx;
return xx;
}
inline __attribute__((always_inline)) bool hasRedundancy_dp(void * addr) {
register uint64_t xx = *((uint64_t*)addr);
return (xx & 0x000f000000000000LL)==0;
}
/***************************************************************************************/
/*********************** floating point full redundancy functions **********************/
/***************************************************************************************/
#if __BYTE_ORDER == __BIG_ENDIAN
typedef union {
float f;
struct {
uint32_t sign : 1;
uint32_t exponent : 8;
uint32_t mantisa : 23;
} parts;
struct {
uint32_t sign : 1;
uint32_t value : 31;
} vars;
} float_cast;
typedef union {
double f;
struct {
uint64_t sign : 1;
uint64_t exponent : 11;
uint64_t mantisa : 52;
} parts;
struct {
uint64_t sign : 1;
uint64_t value : 63;
} vars;
} double_cast;
#elif __BYTE_ORDER == __LITTLE_ENDIAN
typedef union {
float f;
struct {
uint32_t mantisa : 23;
uint32_t exponent : 8;
uint32_t sign : 1;
} parts;
struct {
uint32_t value : 31;
uint32_t sign : 1;
} vars;
} float_cast;
typedef union {
double f;
struct {
uint64_t mantisa : 52;
uint64_t exponent : 11;
uint64_t sign : 1;
} parts;
struct {
uint64_t value : 63;
uint64_t sign : 1;
} vars;
} double_cast;
#else
#error Unknown Byte Order
#endif
template<int start, int end, int incr>
struct UnrolledConjunctionApprox{
// if the mantisa is 0, the value of the double/float var must be 0
static __attribute__((always_inline)) uint64_t BodyZeros(uint8_t* addr){
if(incr==4)
return ((*(reinterpret_cast<float_cast*>(&addr[start]))).vars.value==0) + (UnrolledConjunctionApprox<start+incr,end,incr>::BodyZeros(addr));
else if(incr==8)
return ((*(reinterpret_cast<double_cast*>(&addr[start]))).vars.value==0) + (UnrolledConjunctionApprox<start+incr,end,incr>::BodyZeros(addr));
return 0;
}
static __attribute__((always_inline)) uint64_t BodyRedMap(uint8_t* addr){
if(incr==4)
return count_zero_bytemap_fp((void*)(addr+start)) | (UnrolledConjunctionApprox<start+incr,end,incr>::BodyRedMap(addr)<<SP_MAP_SIZE);
else if(incr==8)
return count_zero_bytemap_dp((void*)(addr+start)) | (UnrolledConjunctionApprox<start+incr,end,incr>::BodyRedMap(addr)<<DP_MAP_SIZE);
else
assert(0 && "Not Supportted floating size! now only support for FP32 or FP64.");
return 0;
}
static __attribute__((always_inline)) uint64_t BodyHasRedundancy(uint8_t* addr){
if(incr==4)
return hasRedundancy_fp((void*)(addr+start)) || (UnrolledConjunctionApprox<start+incr,end,incr>::BodyHasRedundancy(addr));
else if(incr==8)
return hasRedundancy_dp((void*)(addr+start)) || (UnrolledConjunctionApprox<start+incr,end,incr>::BodyHasRedundancy(addr));
else
assert(0 && "Not Supportted floating size! now only support for FP32 or FP64.");
return 0;
}
};
template<int end, int incr>
struct UnrolledConjunctionApprox<end , end , incr>{
static __attribute__((always_inline)) uint64_t BodyZeros(uint8_t* addr){
return 0;
}
static __attribute__((always_inline)) uint64_t BodyRedMap(uint8_t* addr){
return 0;
}
static __attribute__((always_inline)) uint64_t BodyHasRedundancy(uint8_t* addr){
return 0;
}
};
/****************************************************************************************/
inline __attribute__((always_inline)) uint64_t count_zero_bytemap_int8(uint8_t * addr) {
register uint8_t xx = *((uint8_t*)addr);
// reduce by bits until byte level
xx = xx | (xx>>1) | (xx>>2) | (xx>>3) | (xx>>4) | (xx>>5) | (xx>>6) | (xx>>7);
// now xx is byte level reduced, check if it is zero and mask the unused bits
xx = (~xx) & 0x1;
return xx;
}
inline __attribute__((always_inline)) uint64_t count_zero_bytemap_int16(uint8_t * addr) {
register uint16_t xx = *((uint16_t*)addr);
// reduce by bits until byte level
xx = xx | (xx>>1) | (xx>>2) | (xx>>3) | (xx>>4) | (xx>>5) | (xx>>6) | (xx>>7);
// now xx is byte level reduced, check if it is zero and mask the unused bits
xx = (~xx) & 0x101;
// narrowing
xx = xx | (xx>>7);
xx = xx & 0x3;
return xx;
}
inline __attribute__((always_inline)) uint64_t count_zero_bytemap_int32(uint8_t * addr) {
register uint32_t xx = *((uint32_t*)addr);
// reduce by bits until byte level
xx = xx | (xx>>1) | (xx>>2) | (xx>>3) | (xx>>4) | (xx>>5) | (xx>>6) | (xx>>7);
// now xx is byte level reduced, check if it is zero and mask the unused bits
xx = (~xx) & 0x1010101;
// narrowing
xx = xx | (xx>>7);
xx = xx | (xx>>14);
xx = xx & 0xf;
return xx;
}
inline __attribute__((always_inline)) uint64_t count_zero_bytemap_int64(uint8_t * addr) {
register uint64_t xx = *((uint64_t*)addr);
// reduce by bits until byte level
xx = xx | (xx>>1) | (xx>>2) | (xx>>3) | (xx>>4) | (xx>>5) | (xx>>6) | (xx>>7);
// now xx is byte level reduced, check if it is zero and mask the unused bits
xx = (~xx) & 0x101010101010101LL;
// narrowing
xx = xx | (xx>>7);
xx = xx | (xx>>14);
xx = xx | (xx>>28);
xx = xx & 0xff;
return xx;
}
static const unsigned char BitCountTable4[] __attribute__ ((aligned(64))) = {
0, 0, 1, 2
};
static const unsigned char BitCountTable8[] __attribute__ ((aligned(64))) = {
0, 0, 0, 0, 1, 1, 2, 3
};
static const unsigned char BitCountTable16[] __attribute__ ((aligned(64))) = {
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 2, 2, 3, 4
};
static const unsigned char BitCountTable256[] __attribute__ ((aligned(64))) = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8
};
// accessLen & eleSize are size in bits
template<uint32_t AccessLen, uint32_t EleSize>
struct RedMapString {
static __attribute__((always_inline)) std::string getIntRedMapString(uint64_t redmap) {
static_assert(AccessLen % EleSize == 0);
std::string buff =
RedMapString<AccessLen-EleSize, EleSize>::getIntRedMapString(redmap>>(AccessLen-EleSize)) +
" , " + RedMapString<EleSize, EleSize>::getIntRedMapString(redmap);
return buff;
}
};
template<uint32_t AccessLen>
struct RedMapString <AccessLen, AccessLen> {
static __attribute__((always_inline)) std::string getIntRedMapString(uint64_t redmap) {
std::string buff = "";
buff += ((redmap>>(AccessLen-1))&0x1) ? "00 " : "XX ";
buff += RedMapString<AccessLen-1, AccessLen-1>::getIntRedMapString(redmap>>1);
return buff;
}
};
template<>
struct RedMapString <1, 1> {
static __attribute__((always_inline)) std::string getIntRedMapString(uint64_t redmap) {
return std::string((redmap&0x1) ? "00" : "XX");
}
};
template<uint32_t n_exp, uint32_t n_man>
inline __attribute__((always_inline)) std::string __getFpRedMapString(uint64_t redmap) {
std::string buff = "";
const uint32_t signPos = n_exp + n_man;
buff += RedMapString<1,1>::getIntRedMapString(redmap>>signPos) + " | ";
buff += RedMapString<n_exp,n_exp>::getIntRedMapString(redmap>>n_man) + " | ";
buff += RedMapString<n_man,n_man>::getIntRedMapString(redmap);
return buff;
}
template<uint32_t n_exp, uint32_t n_man>
std::string getFpRedMapString(uint64_t redmap, uint64_t accessLen) {
std::string buff = "";
uint64_t newAccessLen = accessLen - (n_exp + n_man + 1);
if(newAccessLen==0) {
return __getFpRedMapString<n_exp,n_man>(redmap);
} else {
return getFpRedMapString<n_exp,n_man>(redmap>>newAccessLen, newAccessLen) + " , " + __getFpRedMapString<n_exp,n_man>(redmap);
}
return buff;
}
#define getFpRedMapString_SP(redmap, num) getFpRedMapString<1,3>(redmap, num*5)
#define getFpRedMapString_DP(redmap, num) getFpRedMapString<2,7>(redmap, num*10)
template<int start, int end, int incr>
struct UnrolledConjunction{
// if the mantisa is 0, the value of the double/float var must be 0
static __attribute__((always_inline)) uint64_t BodyRedNum(uint64_t rmap){
static_assert(start < end);
if(incr==1)
return ((start==0) ? (rmap&0x1) : ((rmap>>start)&0x1)) + (UnrolledConjunction<start+incr,end,incr>::BodyRedNum(rmap));
else if(incr==2)
return ((start==0) ? BitCountTable8[rmap&0x3] : BitCountTable8[(rmap>>start)&0x3]) + (UnrolledConjunction<start+incr,end,incr>::BodyRedNum(rmap));
else if(incr==4)
return ((start==0) ? BitCountTable16[rmap&0xf] : BitCountTable16[(rmap>>start)&0xf]) + (UnrolledConjunction<start+incr,end,incr>::BodyRedNum(rmap));
else if(incr==8)
return ((start==0) ? BitCountTable256[rmap&0xff] : BitCountTable256[(rmap>>start)&0xff]) + (UnrolledConjunction<start+incr,end,incr>::BodyRedNum(rmap));
return 0;
}
static __attribute__((always_inline)) uint64_t BodyRedMap(uint8_t* addr){
static_assert(start < end);
if(incr==1)
return count_zero_bytemap_int8(addr+start) | (UnrolledConjunction<start+incr,end,incr>::BodyRedMap(addr)<<1);
else if(incr==2)
return count_zero_bytemap_int16(addr+start) | (UnrolledConjunction<start+incr,end,incr>::BodyRedMap(addr)<<2);
else if(incr==4)
return count_zero_bytemap_int32(addr+start) | (UnrolledConjunction<start+incr,end,incr>::BodyRedMap(addr)<<4);
else if(incr==8)
return count_zero_bytemap_int64(addr+start) | (UnrolledConjunction<start+incr,end,incr>::BodyRedMap(addr)<<8);
else
assert(0 && "Not Supportted integer size! now only support for INT8, INT16, INT32 or INT64.");
return 0;
}
static __attribute__((always_inline)) bool BodyHasRedundancy(uint8_t* addr){
if(incr==1)
return (addr[start]==0) || (UnrolledConjunction<start+incr,end,incr>::BodyHasRedundancy(addr));
else if(incr==2)
return (((*((uint16_t*)(&addr[start])))&0xff00)==0) || (UnrolledConjunction<start+incr,end,incr>::BodyRedMap(addr));
else if(incr==4)
return (((*((uint32_t*)(&addr[start])))&0xff000000)==0) || (UnrolledConjunction<start+incr,end,incr>::BodyRedMap(addr));
else if(incr==8)
return (((*((uint64_t*)(&addr[start])))&0xff00000000000000LL)==0) || (UnrolledConjunction<start+incr,end,incr>::BodyRedMap(addr));
else
assert(0 && "Not Supportted integer size! now only support for INT8, INT16, INT32 or INT64.");
return 0;
}
};
template<int end, int incr>
struct UnrolledConjunction<end , end , incr>{
static __attribute__((always_inline)) uint64_t BodyRedNum(uint64_t rmap){
return 0;
}
static __attribute__((always_inline)) uint64_t BodyRedMap(uint8_t* addr){
return 0;
}
static __attribute__((always_inline)) uint64_t BodyHasRedundancy(uint8_t* addr){
return 0;
}
};
/*******************************************************************************************/
uint32_t zeros_g=0;
uint64_t map_g=0;
bool is_pointer_valid(void *p) {
/* get the page size */
size_t page_size = sysconf(_SC_PAGESIZE);
/* find the address of the page that contains p */
void *base = (void *)((((size_t)p) / page_size) * page_size);
/* call msync, if it returns non-zero, return false */
return msync(base, page_size, MS_ASYNC) == 0;
}
template<class T, uint32_t AccessLen, bool isApprox>
struct ZeroSpyAnalysis{
static __attribute__((always_inline)) VOID CheckNByteValueAfterRead(ADDRINT ip, void* addr, uint32_t opaqueHandle, THREADID threadId){
// #ifdef DEBUG_ZEROSPY
// fprintf(gDebugFile,"\nINFO : In Check NBytes Value After Read\n");
// #endif
//RedSpyThreadData* const tData = ClientGetTLS(threadId);
#ifdef DEBUG_ZEROSPY
FILE* debug = getDebugFile(threadId);
xed_decoded_inst_t xedd;
xed_decoded_inst_zero_set_mode(&xedd, &LoadSpyGlobals.xedState);
if(XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
char xxx[200] = {0};
xed_decoded_inst_dump (&xedd, xxx, 200);
xed_format_context(XED_SYNTAX_ATT, &xedd, xxx, 200, ip, 0, 0);
fprintf(debug, " IP = %lx %s\n", ip, xxx);
} else {
fprintf(debug, " Failed to disassemble IP = %lx\n",ip);
}
fflush(debug);
#endif
ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
uint8_t* bytes = static_cast<uint8_t*>(addr);
if(isApprox) {
// uint32_t redbyteNum = getRedNum(addr);
bool hasRedundancy = UnrolledConjunctionApprox<0,AccessLen,sizeof(T)>::BodyHasRedundancy(bytes);
if(hasRedundancy) {
uint64_t map = UnrolledConjunctionApprox<0,AccessLen,sizeof(T)>::BodyRedMap(bytes);