FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
daScript/daslib/debug.das at master · feiyunwill/daScript · GitHub
feiyunwill
/
daScript
Public
forked from
GaijinEntertainment/daScript
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Pull requests
0
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
daScript
/
daslib
/
debug.das
Copy path
More file actions
More file actions
Latest commit
History
History
History
2307 lines (2063 loc) · 86.9 KB
Breadcrumbs
daScript
/
daslib
/
debug.das
Copy path
File metadata and controls
2307 lines (2063 loc) · 86.9 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
options
gen2
options
rtti
options
no_aot
options
indenting
=
4
options
no_global_variables
=
false
options
persistent_heap
options
gc
options
strict_smart_pointers
=
true
options
stack
=
4_194_304
module
debug
shared
//! Debug server and Debug Adapter Protocol (DAP) implementation.
//!
//! Provides a full-featured debugger for daslang programs, implementing the
//! `Debug Adapter Protocol <https://microsoft.github.io/debug-adapter-protocol/>`_.
//! Supports breakpoints, stepping, variable inspection, watch expressions,
//! call stacks, and interactive evaluation via a debug agent.
require
math
require
strings
require
daslib
/
rtti
require
daslib
/
debugger
require
daslib
/
fio
require
daslib
/
network
require
uriparser
require
daslib
/
json
require
daslib
/
json_boost
require
daslib
/
defer
require
daslib
/
apply_in_context
require
daslib
/
jobque_boost
require
daslib
/
strings_boost
require
daslib
/
dap
require
daslib
/
debug_eval
let
private
{
LOCAL_VARS
=
1ul
ARGUMENT_VARS
=
2ul
GLOBAL_VARS
=
3ul
STATE_VARS
=
4ul
BLOCKS_POOL
=
4000ul
MAX_STACK
=
1000ul
MAX_VARIABLES
=
10_000_000ul
print_flags_debug
=
(
print_flags
.
escapeString
|
print_flags
.
namesAndDimensions
|
print_flags
.
singleLine
)
}
def
private
push_dap_variable
(
var
res
:
VariablesResponseBody
;
v
:
DAVariable
;
ctxAndFrame
:
uint64
) :
void
{
let
ref
=
v
.
children
!
=
null
?
ctxAndFrame
*
MAX_VARIABLES
+
v
.
uid
: 0ul
res
.
variables
|
>
emplace
(
Variable
(
name
=
v
.
name
,
value
=
v
.
value
,
_type
=
v
.
_type
,
indexedVariables
=
double
(
v
.
indexedVariables
),
variablesReference
=
double
(
ref
)
))
}
def
private
wait_for_resume
(
var
ctxData
:
DAContext
) :
void
{
while
(
!
ctxData
.
continueRequested
&&
!
ctxData
.
stepInRequested
&&
ctxData
.
stepRequestedDepth
==
0
) {
tick_debugger
()
}
ctxData
.
continueRequested
=
false
}
def
private
ctx_at
(
var
ctx
:
Context
) :
DAContextAt
{
unsafe
{
return
intptr
(
addr
(
ctx
))
}
}
def
describe
(
ti
:
rtti
::
TypeInfo
) {
//! Returns a string description of the given type info.
unsafe
{
return
describe
(
addr
(
ti
))
}
}
def
private
get_int_arg
(
args
:
array
<
string
>
;
name
:
string
;
def_val
:
int
) :
int
{
let
idx
=
find_index
(
args
,
name
)
return
idx
>
=
0
&&
idx
+
1
<
length
(
args
) ?
int
(
args
[
idx
+ 1]) :
def_val
}
def
private
ends_with_separator
(
str
:
string
) :
bool
{
for
(
c
in
"
\\
/"
) {
if
(
ends_with
(
str
,
to_char
(
c
)))
return
true
}
return
false
}
def
private
starts_with_separator
(
str
:
string
) :
bool
{
for
(
c
in
"
\\
/"
) {
if
(
starts_with
(
str
,
to_char
(
c
)))
return
true
}
return
false
}
def
private
trim_path
(
path
:
string
) :
string
{
if
(
path
==
"."
)
return
""
if
(
path
|
>
starts_with
(
"./"
)
||
path
|
>
starts_with
(
".
\\
"
))
return
path
|
>
slice
(
2
)
return
path
}
def
private
join_path
(
a
,
path_b
:
string
) :
string
{
let
b
=
trim_path
(
path_b
)
if
(
empty
(
a
))
return
fix_path
(
b
)
if
(
empty
(
b
))
return
fix_path
(
a
)
let
res
=
build_string
()
$
(
builder
) {
builder
|
>
write
(
a
)
let
ends
=
ends_with_separator
(
a
)
let
starts
=
starts_with_separator
(
b
)
if
(
ends
&&
starts
) {
builder
|
>
write
(
slice
(
b
,
1
))
}
elif
(
!
ends
&&
!
starts
) {
builder
|
>
write
(
"/"
)
builder
|
>
write
(
b
)
}
else
{
builder
|
>
write
(
b
)
}
}
return
fix_path
(
res
)
}
def
private
fix_path
(
path
:
string
) :
string
{
return
path
|
>
trim_path
()
|
>
file_name_to_uri
()
|
>
normalize_uri
()
|
>
uri_to_file_name
()
}
def
private
resolve_path
(
path
:
string
;
paths
:
array
<
string
>
) :
string
{
if
(
path
|
>
empty
())
return
path
for
(
it
in
paths
) {
let
newPath
=
it
|
>
join_path
(
path
)
if
(
stat
(
newPath
).
is_valid
)
return
newPath
}
return
fix_path
(
path
)
}
def
private
resolve_path
(
path
:
string
;
paths
:
array
<
string
>
;
aliases
:
table
<
string
;
string
>
) :
string
{
if
(
path
|
>
empty
())
return
path
for
(
k
,
v
in
keys
(
aliases
),
values
(
aliases
)) {
if
(
path
|
>
starts_with
(
k
)) {
let
fixedPath
=
v
|
>
join_path
<
|
slice
(
path
,
length
(
k
))
return
fixedPath
|
>
resolve_path
(
paths
)
}
}
return
path
|
>
resolve_path
(
paths
)
}
def
private
resolve_path_cache
(
path
:
string
;
paths
:
array
<
string
>
;
aliases
:
table
<
string
;
string
>
;
var
cache
:
table
<
string
;
string
>
) :
string
{
if
(
cache
|
>
key_exists
(
path
))
return
cache
?[
path
]
??
""
let
absPath
=
resolve_path
(
path
,
paths
,
aliases
)
cache
|
>
insert
(
path
,
absPath
)
return
absPath
}
def
private
bytes_hr
(
value
:
uint64
) {
if
(
value
>
uint64
(
1024
*
1024
))
return
"
{
float
(
value
)
/
(
1024f
*
1024f
)
}
mb (
{
int
(
value
)
}
)"
if
(
value
>
uint64
(
1024
))
return
"
{
float
(
value
)
/
1024f
}
kb (
{
int
(
value
)
}
)"
return
"
{
int
(
value
)
}
b"
}
class
DAWalker
:
DapiDataWalker
{
//! Data walker for inspecting variables through the Debug Adapter Protocol.
maxChildrenCount : uint = 1000u
varsStack : array<DAVariable?>
@
do_not_delete frame : DAStackFrame ?
inlinePreviewLimit : int = 100
def
startWalk
(
var
f
:
DAStackFrame
;
var
v
:
DAVariable
;
cb
:
block
<
() :
void
>) {
//! Begins walking a stack frame's variable tree, invoking the callback for data traversal.
unsafe
{
frame
=
addr
(
f
)
varsStack
|
>
push
(
addr
(
v
))
}
cb
|
>
invoke
()
frame
=
null
varsStack
|
>
clear
()
}
def
popStack
() {
//! Pops the last variable from the walker's variable stack.
let
n
=
length
(
varsStack
)
if
(
n
>
1
) {
varsStack
|
>
erase
(
n
-
1
)
}
}
def
startCont
() {
//! Initializes the children array for the current variable on the stack.
let
n
=
length
(
varsStack
)
if
(
varsStack
[
n
- 1].
children
==
null
) {
varsStack
[
n
- 1].
children
=
new
array
<
DAVariable
>
()
}
}
def
closeCont
() {
//! Finalizes the current container variable, defaulting its value to its type if empty.
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
if
(
empty
(
v
.
value
)) {
v
.
value
=
v
.
_type
}
}
}
def
override
beforeStructureField
(
ps
:
void
?;
si
:
StructInfo
;
pv
:
void
?;
vi
:
VarInfo
;
last
:
bool
) :
void
{
//! Creates a child variable entry when entering a structure field.
startCont
()
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
ti
=
type_info
(
vi
)
unsafe
{
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
*
v
.
children
|
>
emplace
(
DAVariable
(
uid
=
frame
.
varId
++
,
name
=
vi
.
name
,
_type
=
describe
(
ti
),
address
=
intptr
(
pv
),
size
=
ti
.
size
))
varsStack
|
>
push
(
addr
((
*
v
.
children
)[
length
(
*
v
.
children
)
-
1
]))
}
}
}
def
override
afterStructureField
(
ps
:
void
?;
si
:
StructInfo
;
pv
:
void
?;
vi
:
VarInfo
;
last
:
bool
) :
void
{
//! Finalizes a structure field variable, printing its value if it has no children.
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
if
(
v
.
children
==
null
) {
var
ti
=
type_info
(
vi
)
v
.
value
=
sprint_data_fast
(
pv
,
ti
,
print_flags_debug
)
}
if
(
empty
(
v
.
value
)) {
v
.
value
=
v
.
_type
}
}
popStack
()
}
def
finish_structure_preview
() :
void
{
closeCont
()
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
if
(
v
.
children
!
=
null
) {
v
.
value
=
join_with_names
(
*
v
.
children
,
inlinePreviewLimit
)
}
if
(
empty
(
v
.
value
)) {
v
.
value
=
v
.
_type
}
}
}
def
override
afterStructure
(
ps
:
void
?;
si
:
StructInfo
) :
void
{
//! Finalizes a structure after all fields are walked, building an inline preview.
finish_structure_preview
()
}
def
override
afterStructureCancel
(
ps
:
void
?;
si
:
StructInfo
) :
void
{
//! Handles cancelled structure walking, still building a preview from visited fields.
finish_structure_preview
()
}
def
override
canVisitArray
(
ps
:
void
?;
ti
:
TypeInfo
) :
bool
{
//! Returns true if the array size is within the maximum children limit.
let
arr
=
unsafe
(
reinterpret
<
DapiArray
?
>
(
ps
))
return
arr
.
size
<
=
uint64
(
maxChildrenCount
)
}
def
override
canVisitArrayData
(
ti
:
TypeInfo
;
count
:
uint64
) :
bool
{
//! Returns true if the array data count is within the maximum children limit.
return
count
<
=
uint64
(
maxChildrenCount
)
}
def
override
beforeArrayData
(
ps
:
void
?;
stride
:
uint
;
count
:
uint64
;
ti
:
TypeInfo
) :
void
{
//! Records the array element count on the current variable before walking array data.
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
v
.
indexedVariables
=
uint
(
count
)
}
}
def
override
beforeArrayElement
(
ps
:
void
?;
ti
:
TypeInfo
;
pe
:
void
?;
index
:
uint64
;
last
:
bool
) :
void
{
//! Creates a child variable entry for each array element.
startCont
()
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
unsafe
{
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
*
v
.
children
|
>
emplace
(
DAVariable
(
uid
=
frame
.
varId
++
,
name
=
"
{
int64
(
index
)
}
"
,
_type
=
describe
(
ti
),
address
=
intptr
(
pe
),
size
=
ti
.
size
))
varsStack
|
>
push
(
addr
((
*
v
.
children
)[
length
(
*
v
.
children
)
-
1
]))
}
}
}
def
finish_leaf_value
(
data
:
void
?;
ti
:
TypeInfo
) :
void
{
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
if
(
v
.
children
==
null
) {
unsafe
{
v
.
value
=
sprint_data_fast
(
data
,
addr
(
ti
),
print_flags_debug
)
}
}
if
(
empty
(
v
.
value
)) {
v
.
value
=
v
.
_type
}
}
}
def
override
afterArrayElement
(
ps
:
void
?;
ti
:
TypeInfo
;
pe
:
void
?;
index
:
uint64
;
last
:
bool
) :
void
{
//! Finalizes an array element variable, printing its value if it has no children.
finish_leaf_value
(
pe
,
ti
)
popStack
()
}
def
override
afterArrayData
(
ps
:
void
?;
stride
:
uint
;
count
:
uint64
;
ti
:
TypeInfo
) :
void
{
//! Builds an inline preview string for the array after all elements are walked.
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
if
(
v
.
children
!
=
null
) {
let
preview
=
join
(
*
v
.
children
,
inlinePreviewLimit
)
if
(
!
empty
(
preview
)) {
v
.
value
=
"[
{
int64
(
count
)
}
]
{
preview
}
"
}
}
if
(
empty
(
v
.
value
)) {
v
.
value
=
"[
{
int64
(
count
)
}
]
{
v
.
_type
}
"
}
}
}
def
override
beforeTable
(
pa
:
DapiTable
;
ti
:
TypeInfo
) :
void
{
//! Records the table size on the current variable before walking table entries.
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
v
.
indexedVariables
=
uint
(
pa
.
size
)
}
}
def
override
canVisitTable
(
ps
:
void
?;
ti
:
TypeInfo
) :
bool
{
//! Returns true if the table size is within the maximum children limit.
let
pa
=
unsafe
(
reinterpret
<
DapiTable
?
>
(
ps
))
return
pa
.
size
<
=
uint64
(
maxChildrenCount
)
}
def
override
beforeTableKey
(
pa
:
DapiTable
;
ti
:
TypeInfo
;
pk
:
void
?;
ki
:
TypeInfo
;
index
:
uint64
;
last
:
bool
) :
void
{
//! Creates a child variable entry for a table key.
startCont
()
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
unsafe
{
*
v
.
children
|
>
emplace
(
DAVariable
(
uid
=
frame
.
varId
++
,
name
=
sprint_data
(
pk
,
addr
(
ki
),
print_flags_debug
),
_type
=
describe
(
ki
),
address
=
intptr
(
pk
),
size
=
ki
.
size
))
varsStack
|
>
push
(
addr
((
*
v
.
children
)[
length
(
*
v
.
children
)
-
1
]))
}
}
}
def
override
beforeTableValue
(
pa
:
DapiTable
;
ti
:
TypeInfo
;
pv
:
void
?;
kv
:
TypeInfo
;
index
:
uint64
;
last
:
bool
) :
void
{
//! Updates the type description for the current table value.
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
v
.
_type
=
describe
(
kv
)
}
}
def
override
afterTableValue
(
pa
:
DapiTable
;
ti
:
TypeInfo
;
pv
:
void
?;
kv
:
TypeInfo
;
index
:
uint64
;
last
:
bool
) :
void
{
//! Finalizes a table value variable, printing its value if it has no children.
finish_leaf_value
(
pv
,
kv
)
popStack
()
}
def
override
afterTable
(
pa
:
DapiTable
;
ti
:
TypeInfo
) :
void
{
//! Builds an inline preview string for the table after all entries are walked.
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
if
(
v
.
children
!
=
null
) {
let
preview
=
join_with_names
(
*
v
.
children
,
inlinePreviewLimit
)
if
(
!
empty
(
preview
)) {
v
.
value
=
"[
{
int64
(
pa
.
size
)
}
]
{
preview
}
"
}
}
if
(
empty
(
v
.
value
)) {
v
.
value
=
"[
{
int64
(
pa
.
size
)
}
]
{
v
.
_type
}
"
}
}
}
tupleIndex : int = 0
def
override
beforeTuple
(
ps
:
void
?;
ti
:
TypeInfo
) :
void
{
//! Initializes the container and resets the tuple index before walking tuple entries.
startCont
()
tupleIndex
=
0
}
def
override
beforeTupleEntry
(
ps
:
void
?;
ti
:
TypeInfo
;
pv
:
void
?;
idx
:
int
;
last
:
bool
) :
void
{
//! Creates a child variable entry for a tuple element.
startCont
()
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
let
vi
=
unsafe
(
ti
.
argTypes
[
idx
])
*
v
.
children
|
>
emplace
(
DAVariable
(
uid
=
frame
.
varId
++
,
name
=
"
{
tupleIndex
++
}
"
,
_type
=
describe
(
vi
),
address
=
intptr
(
pv
),
size
=
vi
.
size
))
unsafe
{
varsStack
|
>
push
(
addr
((
*
v
.
children
)[
length
(
*
v
.
children
)
-
1
]))
}
}
}
def
override
afterTupleEntry
(
ps
:
void
?;
ti
:
TypeInfo
;
pv
:
void
?;
idx
:
int
;
last
:
bool
) :
void
{
//! Finalizes a tuple entry variable, printing its value if it has no children.
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
if
(
v
.
children
==
null
) {
unsafe
{
v
.
value
=
sprint_data_fast
(
pv
,
ti
.
argTypes
[
idx
],
print_flags_debug
)
}
}
if
(
empty
(
v
.
value
)) {
v
.
value
=
v
.
_type
}
}
popStack
()
}
def
override
afterTuple
(
ps
:
void
?;
ti
:
TypeInfo
) :
void
{
//! Finalizes a tuple after all entries are walked, building an inline preview.
closeCont
()
let
n
=
length
(
varsStack
)
if
(
n
>
0
) {
var
v
&
=
unsafe
(
varsStack
[
n
- 1])
if
(
v
.
children
!
=
null
) {
v
.
value
=
join
(
*
v
.
children
,
inlinePreviewLimit
)
}
if
(
empty
(
v
.
value
)) {
v
.
value
=
v
.
_type
}
}
}
}
struct
private
DAVariable
{
//! Internal DAP variable representation for the debugger.
uid : uint64
name : string
value : string
_type : string
@
do_not_delete typeInfo : TypeInfo const?
rawValue : float4
indexedVariables : uint
address : uint64
size : uint
children : array<DAVariable>?
}
def
join_with_names
(
a
:
array
<
DAVariable
>
;
limit
:
int
) :
string
{
//! Joins an array of DAVariable into a "name: value" comma-separated string, truncated to the given limit.
return
build_string
()
$
(str) {
var
first
=
true
var
len
=
limit
let
n
=
length
(
a
)
for
(
child
,
idx
in
a
,
range
(
n
)) {
len
-
=
length
(
child
.
name
)
+
length
(
child
.
value
)
+
2
if
(
!
first
) {
str
|
>
write
(
", "
)
len
-
=
2
}
first
=
false
str
|
>
write
(
child
.
name
)
str
|
>
write
(
": "
)
str
|
>
write
(
child
.
value
)
if
(
len
<
=
3
&&
idx
<
n
-
1
) {
str
|
>
write
(
",.."
)
break
}
}
}
}
def
join
(
a
:
array
<
DAVariable
>
;
limit
:
int
) :
string
{
//! Joins DAVariable values into a comma-separated string, truncated to the given limit.
return
build_string
()
$
(str) {
var
first
=
true
let
n
=
length
(
a
)
var
len
=
limit
for
(
v
,
idx
in
a
,
range
(
n
)) {
len
-
=
length
(
v
.
value
)
if
(
!
first
) {
if
(
len
<
=
3
&&
idx
<
n
-
1
) {
str
|
>
write
(
",.."
)
break
}
str
|
>
write
(
", "
)
len
-
=
2
}
first
=
false
str
|
>
write
(
v
.
value
)
}
}
}
def
find_child_var
(
val
:
DAVariable
;
id
:
uint64
;
cb
:
block
<
(
res
:
DAVariable
) :
void
>) {
//! Recursively searches the variable tree for a child with the given uid, invoking the callback if found.
if
(
val
.
uid
==
id
) {
cb
|
>
invoke
(
val
)
return
true
}
if
(
val
.
children
!
=
null
) {
for
(
c
in
*
val
.
children
) {
if
(
c
|
>
find_child_var
(
id
,
cb
))
return
true
}
}
return
false
}
def
find_child_var
(
val
:
array
<
DAVariable
>
;
cb
:
block
<
(
res
:
DAVariable
) :
bool
>) {
//! Searches an array of DAVariable trees using a predicate callback.
for
(
v
in
val
) {
if
(
v
|
>
find_child_var
(
cb
))
return
true
}
return
false
}
def
find_child_var
(
val
:
DAVariable
;
cb
:
block
<
(
res
:
DAVariable
) :
bool
>) {
//! Recursively searches the variable tree using a predicate callback.
if
(
cb
|
>
invoke
(
val
))
return
true
if
(
val
.
children
!
=
null
) {
for
(
c
in
*
val
.
children
) {
if
(
c
|
>
find_child_var
(
cb
))
return
true
}
}
return
false
}
struct
private
DAStackFrame
{
//! Internal DAP stack frame representation for the debugger.
name : string
path : string
@
do_not_delete func : FuncInfo?
isBlock : bool = false
spAddr : uint64 = 0ul
line : uint = 1u
variables : array<DAVariable>
arguments : array<DAVariable>
globals : array<DAVariable>
state : array<tuple<uid : uint64; name : string; vars : array<DAVariable>>>
varId : uint64 = BLOCKS_POOL + 1ul
}
def
find_child_var
(
stack
:
DAStackFrame
;
id
:
uint64
;
cb
:
block
<
(
res
:
DAVariable
) :
void
>) {
//! Finds a variable by uid across all scopes (locals, arguments, globals, state) of a stack frame.
for
(
c
in
stack
.
variables
) {
if
(
c
|
>
find_child_var
(
id
,
cb
))
return
}
for
(
c
in
stack
.
arguments
) {
if
(
c
|
>
find_child_var
(
id
,
cb
))
return
}
for
(
c
in
stack
.
globals
) {
if
(
c
|
>
find_child_var
(
id
,
cb
))
return
}
for
(
c
in
stack
.
state
) {
for
(
v
in
c
.
vars
) {
if
(
v
|
>
find_child_var
(
id
,
cb
))
return
}
}
}
def
find_child_var
(
stack
:
DAStackFrame
;
cb
:
block
<
(
res
:
DAVariable
;
idx
:
uint64
) :
bool
>) :
bool
{
//! Searches all stack frame scopes with a predicate, passing the scope category for each variable.
for
(
c
in
stack
.
variables
) {
if
(
cb
|
>
invoke
(
c
,
LOCAL_VARS
))
return
true
}
for
(
c
in
stack
.
arguments
) {
if
(
cb
|
>
invoke
(
c
,
ARGUMENT_VARS
))
return
true
}
for
(
c
in
stack
.
globals
) {
if
(
cb
|
>
invoke
(
c
,
GLOBAL_VARS
))
return
true
}
for
(
idx
,
c
in
iter_range
(
stack
.
state
),
stack
.
state
) {
for
(
v
in
c
.
vars
) {
if
(
cb
|
>
invoke
(
v
,
STATE_VARS
+
uint64
(
idx
)))
return
true
}
}
return
false
}
def
iter_top_child_var
(
stack
:
DAStackFrame
;
cb
:
block
<
(
res
:
DAVariable
) :
void
>) {
//! Iterates over all top-level variables (locals, arguments, globals) in the stack frame.
for
(
c
in
stack
.
variables
) {
cb
|
>
invoke
(
c
)
}
for
(
c
in
stack
.
arguments
) {
cb
|
>
invoke
(
c
)
}
for
(
c
in
stack
.
globals
) {
cb
|
>
invoke
(
c
)
}
}
class
private
DAStackWalker
:
DapiStackWalker
{
//! Stack walker that collects frames for the DAP debugger.
dataWalker : DAWalker?
collectAllGlobals : bool = false
wasGlobalsCollected : bool = false
@
do_not_delete ctx : DAContext?
@
do_not_delete workingPaths : array<string>?
@
do_not_delete pathAliases : table<string; string>?
@
do_not_delete pathsCache : table<string; string>?
def
DAStackWalker
() {
//! Constructs a DAStackWalker and initializes its data walker.
dataWalker
=
new
DAWalker
()
}
def
operator
delete
{
//! Cleans up the data walker.
unsafe
{
delete
dataWalker
}
}
def
collectGlobalAt
(
vinfo
:
VarInfo
;
var
frame
:
DAStackFrame
&
) {
//! Collects a single global variable by name and adds it to the stack frame's globals.
var
value
:
void
?
unsafe
{
value
=
get_context_global_variable
(
ctx
.
ctx
,
vinfo
.
name
)
}
let
ti
=
type_info
(
vinfo
)
var
global
=
DAVariable
(
uid
=
frame
.
varId
++
,
name
=
vinfo
.
name
,
_type
=
describe
(
ti
),
address
=
intptr
(
value
),
size
=
ti
.
size
,
typeInfo
=
ti
)
if
(
ti
!
=
null
) {
dataWalker
->
startWalk
(
frame
,
global
)
$
{
make_data_walker
(
dataWalker
)
$
(adapter) {
adapter
|
>
walk_data
(
value
,
*
ti
)
}
}
}
if
(
global
.
children
==
null
) {
global
.
value
=
sprint_data_fast
(
value
,
ti
,
print_flags_debug
)
}
if
(
empty
(
global
.
value
)) {
global
.
value
=
global
.
_type
}
frame
.
globals
|
>
emplace
(
global
)
}
def
collectGlobals
() {
//! Collects all global variables from the debugged context into the top stack frame.
if
(
wasGlobalsCollected
)
return
wasGlobalsCollected
=
true
let
stackLen
=
length
(
ctx
.
stack
)
if
(
stackLen
==
0
)
return
var
frame
&
=
unsafe
(
ctx
.
stack
[
stackLen
- 1])
if
(
collectAllGlobals
) {
for
(
i
in
range
(
get_total_variables
(
*
ctx
.
ctx
))) {
let
vinfo
&
=
unsafe
(
get_variable_info
(
ctx
.
ctx
,
i
))
if
(
vinfo
.
name
|
>
starts_with
(
"g```"
)
||
vinfo
.
name
==
"__rtti_require"
)
continue
collectGlobalAt
(
vinfo
,
frame
)
}
return
}
if
(
frame
.
func
!
=
null
) {
for
(
i
in
range
(
frame
.
func
.
globalCount
)) {
let
vinfo
=
unsafe
(
frame
.
func
.
globals
[
i
])
if
(
vinfo
.
name
|
>
starts_with
(
"g```"
)
||
vinfo
.
name
==
"__rtti_require"
)
continue
collectGlobalAt
(
*
vinfo
,
frame
)
}
}
}
def
override
onCallAOT
(
pp
:
Prologue
;
fileName
:
string
#) :
void
{
//! Handles an AOT function call event, updating the current stack frame with AOT call info.
let
n
=
length
(
ctx
.
stack
)
if
(
n
>
0
) {
ctx
.
stack
[
n
- 1].
name
=
pp
.
info
!
=
null
?
"def
{
pp
.
info
.
name
}
[AOT]"
:
"def [AOT]"
ctx
.
stack
[
n
- 1].
path
=
"
{
fileName
}
"
collectGlobals
()
}
}
def
override
onCallJIT
(
pp
:
Prologue
;
fileName
:
string
#) :
void
{
//! Handles a JIT function call event, updating the current stack frame with JIT call info.
let
n
=
length
(
ctx
.
stack
)
if
(
n
>
0
) {
ctx
.
stack
[
n
- 1].
name
=
pp
.
info
!
=
null
?
"def
{
pp
.
info
.
name
}
[JIT]"
:
"def [JIT]"
ctx
.
stack
[
n
- 1].
path
=
"
{
fileName
}
"
collectGlobals
()
}
}
def
override
onCallAt
(
pp
:
Prologue
;
info
:
FuncInfo
;
at
:
LineInfo
) :
void
{
//! Handles a function call event with source location, updating the stack frame name, path, and line.
let
n
=
length
(
ctx
.
stack
)
if
(
n
>
0
) {
ctx
.
stack
[
n
- 1].
name
=
"def
{
info
.
name
}
"
ctx
.
stack
[
n
- 1].
path
=
"
{
at
.
fileInfo
.
name
}
"
|
>
resolve_path_cache
(
*
workingPaths
,
*
pathAliases
,
*
pathsCache
)
ctx
.
stack
[
n
- 1].
line
=
at
.
line
collectGlobals
()
}
}
def
override
onCall
(
pp
:
Prologue
;
info
:
FuncInfo
) :
void
{
//! Handles a function call event without source location, updating the stack frame name.
let
n
=
length
(
ctx
.
stack
)
if
(
n
>
0
) {
ctx
.
stack
[
n
- 1].
name
=
"def
{
info
.
name
}
"
collectGlobals
()
}
}
def
override
onBeforeCall
(
pp
:
Prologue
;
sp
:
void
?) :
void
{
//! Pushes a new stack frame onto the context stack before a function or block call.
let
iblock
=
intptr
(
pp
.
_block
)
let
isBlock
=
(
iblock
&
1ul)
!
=
0ul
let
funcInfo
=
isBlock
?
default
<
FuncInfo
?
>
:
pp
.
info
ctx
.
stack
|
>
emplace
(
DAStackFrame
(
func
=
unsafe
(
reinterpret
<
FuncInfo
?
>
(
funcInfo
)),
isBlock
=
isBlock
,
spAddr
=
intptr
(
sp
)))
}
def
override
onVariable
(
inf
:
FuncInfo
;
vinfo
:
LocalVariableInfo
;
arg
:
void
?;
inScope
:
bool
) :
void
{
//! Collects a local variable from the current stack frame into the debug variable list.
if
(
!
inScope
)
return
let
stackLen
=
length
(
ctx
.
stack
)
if
(
stackLen
>
0
) {
var
frame
&
=
unsafe
(
ctx
.
stack
[
stackLen
- 1])
var
ti
=
type_info
(
vinfo
)
var
variable
=
DAVariable
(
uid
=
frame
.
varId
++
,
name
=
vinfo
.
name
,
_type
=
describe
(
ti
),
address
=
intptr
(
arg
),
size
=
ti
.
size
,
typeInfo
=
ti
)
if
(
ti
!
=
null
) {
dataWalker
->
startWalk
(
frame
,
variable
)
$
{
make_data_walker
(
dataWalker
)
$
(adapter) {
adapter
|
>
walk_data
(
arg
,
*
ti
)
}
}
}
if
(
variable
.
children
==
null
) {
let
value
=
!
inScope
?
"<uninitialized>"
:
arg
!
=
null
?
sprint_data_fast
(
arg
,
ti
,
print_flags_debug
) :
"<optimized>"
variable
.
value
=
value
}
elif
(
empty
(
variable
.
value
)) {
variable
.
value
=
variable
.
_type
}
frame
.
variables
|
>
emplace
(
variable
)
}
}
def
override
onArgument
(
inf
:
FuncInfo
;
index
:
int
;
vinfo
:
VarInfo
;
arg
:
float4
) {
//! Collects a function argument from the current stack frame into the debug argument list.
let
stackLen
=
length
(
ctx
.
stack
)
if
(
stackLen
>
0
) {
var
frame
&
=
unsafe
(
ctx
.
stack
[
stackLen
- 1])
let
ti
=
type_info
(
vinfo
)
var
variable
=
DAVariable
(
uid
=
frame
.
varId
++
,
name
=
vinfo
.
name
,
_type
=
describe
(
ti
),
address
=
ti
.
isRef
?
intptr
(
unsafe
(
reinterpret
<
void
?
>
(
arg
))) : 0ul,
size
=
ti
.
size
,
typeInfo
=
ti
,
rawValue
=
arg
)
if
(
ti
!
=
null
) {
dataWalker
->
startWalk
(
frame
,
variable
)
$
{
make_data_walker
(
dataWalker
)
$
(adapter) {
adapter
|
>
walk_data
(
arg
,
*
ti
)
}
}
}
if
(
variable
.
children
==
null
) {
variable
.
value
=
sprint_data_fast
(
arg
,
ti
,
print_flags_debug
)
}
if
(
empty
(
variable
.
value
)) {
variable
.
value
=
variable
.
_type
}
frame
.
arguments
|
>
emplace
(
variable
)
}
}
}
enum
DABreakpointState
{
//! State of a DAP breakpoint during its lifecycle.
Uninitialized
=
0
Initialized
Instrumented
}
//! Opaque handle representing a debug context pointer.
typedef
DAContextAt
=
uint64
struct
private
DABreakpoint
{
//! Internal breakpoint descriptor for the DAP debugger.
id : uint64
line : uint
prevState : DABreakpointState
state : DABreakpointState
ctxAt : DAContextAt
}
//! Mapping from source file path to its list of breakpoints.
typedef
DABreakpoints
=
table
<
string
;
array
<
DABreakpoint
>>
struct
private
DAContext
{
//! Internal context state for the DAP debugger.
id : uint64
at : DAContextAt
@
do_not_delete ctx : Context?
stack : array<DAStackFrame>
continueRequested : bool = false
pauseRequested : bool = false
stepInRequested : bool = false
stepRequestedDepth : int = 0
}
def
private
reset_debug_flags
(
var
ctx
:
DAContext
) {
ctx
.
continueRequested
=
false
ctx
.
pauseRequested
=
false
ctx
.
stepInRequested
=
false
ctx
.
stepRequestedDepth
=
0
}
def
private
to_string
(
ctx
:
DAContext
) {
return
build_string
()
$
(str) {
if
(
ctx
.
ctx
.
category
.
debugger_attached
) {
str
|
>
write
(
"*"
)
}
let
ctxNameLen
=
length
(
ctx
.
ctx
.
name
)
if
(
ctxNameLen
>
0
) {
str
|
>
write
(
ctx
.
ctx
.
name
)
}
else
{
str
|
>
write
(
ctx
.
at
)
}
if
(
int
(
ctx
.
ctx
.
category
)
>
0
) {
str
|
>
write
(
" "
)
str
|
>
write
(
ctx
.
ctx
.
category
)
}
if
(
ctxNameLen
>
0
) {
str
|
>
write
(
" "
)
str
|
>
write
(
ctx
.
at
)
}
str
|
>
write
(
" ("
)
str
|
>
write
(
int64
(
ctx
.
id
))
str
|
>
write
(
")"
)
}
}
def
private
compare_path
(
p1
,
p2
:
string
) {
if
(
p1
==
p2
)
return
true
return
to_lower
(
p1
)
==
to_lower
(
p2
)
}
class
private
DAgent
:
DapiDebugAgent
{
//! Main debug agent implementing the DAP protocol.
walker : DAStackWalker?
server : DAServer?
breakpoints : DABreakpoints
breakpointId : uint64 = 1ul
contexts : array<DAContext>
contextId : uint64 = 1ul
waitConnection : bool = true
withInstruments : bool = false
workingPaths : array<string>
pathAliases : table<string; string>
pathsCache : table<string; string>
collectingAgentData : bool = false
logStrMemory = false
initialStrLimit = uint64(8 * 1024 * 1024)
strLimit : uint64 = uint64(8 * 1024 * 1024)
pauseCtx : rtti::Context? = null
pauseAt : LineInfo const? = null
evalFrame : DAStackFrame <- DAStackFrame()
hwBreakpoints : array<int>
def
initAgent
(
var
ctx
:
Context
) {
//! Initializes the debug agent, creates the stack walker, starts the server, and registers the initial contexts.
waitConnection
=
wait_debugger
()
withInstruments
=
use_instruments
()
walker
=
new
DAStackWalker
()
unsafe
{
walker
.
workingPaths
=
addr
(
workingPaths
)
walker
.
pathAliases
=
addr
(
pathAliases
)
walker
.
pathsCache
=
addr
(
pathsCache
)
}
startServer
()
addContext
(
ctx
)
addContext
(
this_context
())
}
def
startServer
() {
//! Creates and starts the DAP debug server on the configured port.
let
args
<
-
get_command_line_arguments
()
let
port
=
args
|
>
get_int_arg
(
"--das-debug-port"
,
10000
)
server
=
new
DAServer
()
server
.
port
=
port
unsafe
{
server
.
agent
=
addr
(
self
)
}
server
->
make_server_adapter
()
if
(
!
server
->
init
(
port
)) {
to_log
(
LOG_ERROR
,
"debug server failed to initialize
\n
"
)
unsafe
{
delete
server
}
}
}
def
addPath
(
path
:
string
) {
//! Adds a source path to the working paths list if not already present.
if
(
workingPaths
|
>
find_index
(
path
)
<
0
) {
workingPaths
|
>
push
(
path
)
}
}
def
setPaths
(
paths
:
array
<
string
>
;
aliases
:
table
<
string
;
string
>
) {
//! Sets source paths and path aliases used for resolving file locations in the debugger.
workingPaths
|
>
clear
()
pathsCache
|
>
clear
()
for
(
path
in
paths
) {
addPath
(
path
)
}
let
dasRoot
=
get_das_root
()
if
(
!
empty
(
dasRoot
)
&&
dasRoot
!
=
"."
) {
addPath
(
dasRoot
|
>
join_path
(
"daslib"
))
addPath
(
dasRoot
|
>
join_path
(
"src/builtin"
))
}
pathAliases
|
>
clear
()
for
(
k
,
v
in
keys
(
aliases
),
values
(
aliases
)) {
pathAliases
|
>
insert
(
k
,
v
)
}
}
def
override
onUninstall
(
agent
:
DebugAgent
?) {
//! Handles agent uninstall by deleting self when the agent matches.
if
(
agent
==
thisAgent
) {
delete
self
}
}
def
operator
delete
{
//! Cleans up the stack walker and server resources.
unsafe
{
delete
walker
delete
server
}
}
def
log
(
msg
:
string
) {
//! Logs a message through the debug server, or prints to stdout if no server is available.
if
(
server
!
=
null
) {
server
->
log
(
msg
)
}
else
{
print
(
"
{
msg
}
\n
"
)
}
View remainder of file in raw view
Back
|
FazBrowse Home
|
New Git URL