1const StackTrace = @This();
2
3const builtin = @import("builtin");
4
5const std = @import("std");
6const Step = std.Build.Step;
7const OptimizeMode = std.lang.Optimize;
8const mem = std.mem;
9
10const tests = @import("../tests.zig");
11const stack_traces_cases = @import("../stack_traces.zig");
12
13b: *std.Build,
14step: *Step,
15options: Options,
16convert_exe: *std.Build.Step.Compile,
17
18pub const Options = struct {
19 test_filters: []const []const u8,
20 test_target_filters: []const []const u8,
21 test_extra_targets: bool,
22 optimize_modes: []const OptimizeMode,
23 skip_non_native: bool,
24 skip_freebsd: bool,
25 skip_netbsd: bool,
26 skip_openbsd: bool,
27 skip_windows: bool,
28 skip_darwin: bool,
29 skip_linux: bool,
30 skip_llvm: bool,
31 skip_libc: bool,
32};
33
34pub const CaseParameters = struct {
35 linkage: ?std.builtin.LinkMode = null,
36 target: std.Target.Query = .{},
37 optimize: std.lang.Optimize = .debug,
38 link_libc: ?bool = null,
39 use_llvm: ?bool = null,
40 use_lld: ?bool = null,
41 pie: ?bool = null,
42 /// To enable this coverage, one of two things needs to happen:
43 /// * The compiler needs to gain the ability to strip only debug info (not symbols)
44 /// * `std.Build.Step.ObjCopy` needs to be un-regressed
45 strip: ?bool = false,
46
47 // This is intended for targets that, for any reason, shouldn't be run as part of a normal test
48 // invocation. This could be because of a slow backend, requiring a newer LLVM version, being
49 // too niche, etc.
50 extra_target: bool = false,
51};
52
53/// Only add a non-native target to this set if there's a way to emulate it, or if it can built on a
54/// platform with the same arch/OS but has a different ABI. For example, it makes little sense to
55/// add `riscv64-netbsd` here because there's no QEMU user-mode emulation for it anyway, and it'll
56/// still be covered by the native entries when run on a real `riscv64-netbsd` system. But adding
57/// `aarch64-windows-msvc` is valuable because the native entries will default to `gnu` on Windows.
58pub const param_sets = [_]CaseParameters{
59 .{},
60 .{
61 .link_libc = true,
62 },
63 .{
64 .pie = true,
65 },
66 .{
67 .link_libc = true,
68 .pie = true,
69 },
70
71 // FreeBSD Targets
72
73 .{
74 .target = .{
75 .cpu_arch = .arm,
76 .os_tag = .freebsd,
77 .abi = .eabihf,
78 },
79 },
80
81 .{
82 .target = .{
83 .cpu_arch = .x86,
84 .os_tag = .freebsd,
85 .abi = .none,
86 },
87 },
88
89 // Linux Targets
90
91 .{
92 .target = .{
93 .cpu_arch = .aarch64,
94 .os_tag = .linux,
95 .abi = .none,
96 },
97 },
98 .{
99 .target = .{
100 .cpu_arch = .aarch64,
101 .os_tag = .linux,
102 .abi = .musl,
103 },
104 .link_libc = true,
105 },
106 .{
107 .target = .{
108 .cpu_arch = .aarch64,
109 .os_tag = .linux,
110 .abi = .musl,
111 },
112 .linkage = .dynamic,
113 .link_libc = true,
114 .extra_target = true,
115 },
116 .{
117 .target = .{
118 .cpu_arch = .aarch64,
119 .os_tag = .linux,
120 .abi = .gnu,
121 },
122 .link_libc = true,
123 },
124
125 .{
126 .target = .{
127 .cpu_arch = .aarch64_be,
128 .os_tag = .linux,
129 .abi = .none,
130 },
131 },
132 .{
133 .target = .{
134 .cpu_arch = .aarch64_be,
135 .os_tag = .linux,
136 .abi = .musl,
137 },
138 .link_libc = true,
139 },
140 .{
141 .target = .{
142 .cpu_arch = .aarch64_be,
143 .os_tag = .linux,
144 .abi = .musl,
145 },
146 .linkage = .dynamic,
147 .link_libc = true,
148 .extra_target = true,
149 },
150 .{
151 .target = .{
152 .cpu_arch = .aarch64_be,
153 .os_tag = .linux,
154 .abi = .gnu,
155 },
156 .link_libc = true,
157 },
158
159 .{
160 .target = .{
161 .cpu_arch = .arm,
162 .os_tag = .linux,
163 .abi = .eabihf,
164 },
165 },
166 .{
167 .target = .{
168 .cpu_arch = .arm,
169 .os_tag = .linux,
170 .abi = .musleabihf,
171 },
172 .link_libc = true,
173 },
174 .{
175 .target = .{
176 .cpu_arch = .arm,
177 .os_tag = .linux,
178 .abi = .musleabihf,
179 },
180 .linkage = .dynamic,
181 .link_libc = true,
182 .extra_target = true,
183 },
184 .{
185 .target = .{
186 .cpu_arch = .arm,
187 .os_tag = .linux,
188 .abi = .gnueabihf,
189 },
190 .link_libc = true,
191 },
192
193 .{
194 .target = .{
195 .cpu_arch = .armeb,
196 .os_tag = .linux,
197 .abi = .eabihf,
198 },
199 },
200 .{
201 .target = .{
202 .cpu_arch = .armeb,
203 .os_tag = .linux,
204 .abi = .musleabihf,
205 },
206 .link_libc = true,
207 },
208 // Crashes in weird ways when applying relocations.
209 // .{
210 // .target = .{
211 // .cpu_arch = .armeb,
212 // .os_tag = .linux,
213 // .abi = .musleabihf,
214 // },
215 // .linkage = .dynamic,
216 // .link_libc = true,
217 // .extra_target = true,
218 // },
219 .{
220 .target = .{
221 .cpu_arch = .armeb,
222 .os_tag = .linux,
223 .abi = .gnueabihf,
224 },
225 .link_libc = true,
226 },
227
228 .{
229 .target = .{
230 .cpu_arch = .hexagon,
231 .os_tag = .linux,
232 .abi = .none,
233 },
234 },
235 .{
236 .target = .{
237 .cpu_arch = .hexagon,
238 .os_tag = .linux,
239 .abi = .musl,
240 },
241 .link_libc = true,
242 },
243 .{
244 .target = .{
245 .cpu_arch = .hexagon,
246 .os_tag = .linux,
247 .abi = .musl,
248 },
249 .linkage = .dynamic,
250 .link_libc = true,
251 .extra_target = true,
252 },
253
254 .{
255 .target = .{
256 .cpu_arch = .loongarch32,
257 .os_tag = .linux,
258 .abi = .none,
259 },
260 },
261 .{
262 .target = .{
263 .cpu_arch = .loongarch32,
264 .os_tag = .linux,
265 .abi = .gnu,
266 },
267 .link_libc = true,
268 },
269
270 .{
271 .target = .{
272 .cpu_arch = .loongarch64,
273 .os_tag = .linux,
274 .abi = .none,
275 },
276 },
277 .{
278 .target = .{
279 .cpu_arch = .loongarch64,
280 .os_tag = .linux,
281 .abi = .musl,
282 },
283 .link_libc = true,
284 },
285 .{
286 .target = .{
287 .cpu_arch = .loongarch64,
288 .os_tag = .linux,
289 .abi = .musl,
290 },
291 .linkage = .dynamic,
292 .link_libc = true,
293 .extra_target = true,
294 },
295 .{
296 .target = .{
297 .cpu_arch = .loongarch64,
298 .os_tag = .linux,
299 .abi = .gnu,
300 },
301 .link_libc = true,
302 },
303
304 .{
305 .target = .{
306 .cpu_arch = .mips,
307 .os_tag = .linux,
308 .abi = .eabihf,
309 },
310 },
311 .{
312 .target = .{
313 .cpu_arch = .mips,
314 .os_tag = .linux,
315 .abi = .musleabihf,
316 },
317 .link_libc = true,
318 },
319 .{
320 .target = .{
321 .cpu_arch = .mips,
322 .os_tag = .linux,
323 .abi = .musleabihf,
324 },
325 .linkage = .dynamic,
326 .link_libc = true,
327 .extra_target = true,
328 },
329 .{
330 .target = .{
331 .cpu_arch = .mips,
332 .os_tag = .linux,
333 .abi = .gnueabihf,
334 },
335 .link_libc = true,
336 },
337
338 .{
339 .target = .{
340 .cpu_arch = .mipsel,
341 .os_tag = .linux,
342 .abi = .eabihf,
343 },
344 },
345 .{
346 .target = .{
347 .cpu_arch = .mipsel,
348 .os_tag = .linux,
349 .abi = .musleabihf,
350 },
351 .link_libc = true,
352 },
353 .{
354 .target = .{
355 .cpu_arch = .mipsel,
356 .os_tag = .linux,
357 .abi = .musleabihf,
358 },
359 .linkage = .dynamic,
360 .link_libc = true,
361 .extra_target = true,
362 },
363 .{
364 .target = .{
365 .cpu_arch = .mipsel,
366 .os_tag = .linux,
367 .abi = .gnueabihf,
368 },
369 .link_libc = true,
370 },
371
372 .{
373 .target = .{
374 .cpu_arch = .mips64,
375 .os_tag = .linux,
376 .abi = .none,
377 },
378 },
379 .{
380 .target = .{
381 .cpu_arch = .mips64,
382 .os_tag = .linux,
383 .abi = .abin32,
384 },
385 },
386 .{
387 .target = .{
388 .cpu_arch = .mips64,
389 .os_tag = .linux,
390 .abi = .muslabi64,
391 },
392 .link_libc = true,
393 },
394 .{
395 .target = .{
396 .cpu_arch = .mips64,
397 .os_tag = .linux,
398 .abi = .muslabi64,
399 },
400 .linkage = .dynamic,
401 .link_libc = true,
402 .extra_target = true,
403 },
404 .{
405 .target = .{
406 .cpu_arch = .mips64,
407 .os_tag = .linux,
408 .abi = .muslabin32,
409 },
410 .link_libc = true,
411 },
412 .{
413 .target = .{
414 .cpu_arch = .mips64,
415 .os_tag = .linux,
416 .abi = .muslabin32,
417 },
418 .linkage = .dynamic,
419 .link_libc = true,
420 .extra_target = true,
421 },
422 .{
423 .target = .{
424 .cpu_arch = .mips64,
425 .os_tag = .linux,
426 .abi = .gnuabi64,
427 },
428 .link_libc = true,
429 },
430 .{
431 .target = .{
432 .cpu_arch = .mips64,
433 .os_tag = .linux,
434 .abi = .gnuabin32,
435 },
436 .link_libc = true,
437 },
438
439 .{
440 .target = .{
441 .cpu_arch = .mips64el,
442 .os_tag = .linux,
443 .abi = .none,
444 },
445 },
446 .{
447 .target = .{
448 .cpu_arch = .mips64el,
449 .os_tag = .linux,
450 .abi = .abin32,
451 },
452 },
453 .{
454 .target = .{
455 .cpu_arch = .mips64el,
456 .os_tag = .linux,
457 .abi = .muslabi64,
458 },
459 .link_libc = true,
460 },
461 .{
462 .target = .{
463 .cpu_arch = .mips64el,
464 .os_tag = .linux,
465 .abi = .muslabi64,
466 },
467 .linkage = .dynamic,
468 .link_libc = true,
469 .extra_target = true,
470 },
471 .{
472 .target = .{
473 .cpu_arch = .mips64el,
474 .os_tag = .linux,
475 .abi = .muslabin32,
476 },
477 .link_libc = true,
478 .extra_target = true,
479 },
480 .{
481 .target = .{
482 .cpu_arch = .mips64el,
483 .os_tag = .linux,
484 .abi = .muslabin32,
485 },
486 .linkage = .dynamic,
487 .link_libc = true,
488 .extra_target = true,
489 },
490 .{
491 .target = .{
492 .cpu_arch = .mips64el,
493 .os_tag = .linux,
494 .abi = .gnuabi64,
495 },
496 .link_libc = true,
497 },
498 .{
499 .target = .{
500 .cpu_arch = .mips64el,
501 .os_tag = .linux,
502 .abi = .gnuabin32,
503 },
504 .link_libc = true,
505 .extra_target = true,
506 },
507
508 .{
509 .target = .{
510 .cpu_arch = .powerpc,
511 .os_tag = .linux,
512 .abi = .eabihf,
513 },
514 },
515 .{
516 .target = .{
517 .cpu_arch = .powerpc,
518 .os_tag = .linux,
519 .abi = .musleabihf,
520 },
521 .link_libc = true,
522 },
523 .{
524 .target = .{
525 .cpu_arch = .powerpc,
526 .os_tag = .linux,
527 .abi = .musleabihf,
528 },
529 .linkage = .dynamic,
530 .link_libc = true,
531 .extra_target = true,
532 },
533
534 .{
535 .target = .{
536 .cpu_arch = .powerpc64,
537 .os_tag = .linux,
538 .abi = .none,
539 },
540 },
541 .{
542 .target = .{
543 .cpu_arch = .powerpc64,
544 .os_tag = .linux,
545 .abi = .musl,
546 },
547 .link_libc = true,
548 },
549 .{
550 .target = .{
551 .cpu_arch = .powerpc64,
552 .os_tag = .linux,
553 .abi = .musl,
554 },
555 .linkage = .dynamic,
556 .link_libc = true,
557 .extra_target = true,
558 },
559
560 .{
561 .target = .{
562 .cpu_arch = .powerpc64le,
563 .os_tag = .linux,
564 .abi = .none,
565 },
566 },
567 .{
568 .target = .{
569 .cpu_arch = .powerpc64le,
570 .os_tag = .linux,
571 .abi = .musl,
572 },
573 .link_libc = true,
574 },
575 .{
576 .target = .{
577 .cpu_arch = .powerpc64le,
578 .os_tag = .linux,
579 .abi = .musl,
580 },
581 .linkage = .dynamic,
582 .link_libc = true,
583 .extra_target = true,
584 },
585 .{
586 .target = .{
587 .cpu_arch = .powerpc64le,
588 .os_tag = .linux,
589 .abi = .gnu,
590 },
591 .link_libc = true,
592 },
593
594 .{
595 .target = .{
596 .cpu_arch = .riscv32,
597 .os_tag = .linux,
598 .abi = .none,
599 },
600 },
601 .{
602 .target = .{
603 .cpu_arch = .riscv32,
604 .os_tag = .linux,
605 .abi = .musl,
606 },
607 .link_libc = true,
608 },
609 .{
610 .target = .{
611 .cpu_arch = .riscv32,
612 .os_tag = .linux,
613 .abi = .musl,
614 },
615 .linkage = .dynamic,
616 .link_libc = true,
617 .extra_target = true,
618 },
619 .{
620 .target = .{
621 .cpu_arch = .riscv32,
622 .os_tag = .linux,
623 .abi = .gnu,
624 },
625 .link_libc = true,
626 },
627
628 .{
629 .target = .{
630 .cpu_arch = .riscv64,
631 .os_tag = .linux,
632 .abi = .none,
633 },
634 },
635 .{
636 .target = .{
637 .cpu_arch = .riscv64,
638 .os_tag = .linux,
639 .abi = .musl,
640 },
641 .link_libc = true,
642 },
643 .{
644 .target = .{
645 .cpu_arch = .riscv64,
646 .os_tag = .linux,
647 .abi = .musl,
648 },
649 .linkage = .dynamic,
650 .link_libc = true,
651 .extra_target = true,
652 },
653 .{
654 .target = .{
655 .cpu_arch = .riscv64,
656 .os_tag = .linux,
657 .abi = .gnu,
658 },
659 .link_libc = true,
660 },
661
662 .{
663 .target = .{
664 .cpu_arch = .s390x,
665 .os_tag = .linux,
666 .abi = .none,
667 },
668 },
669 .{
670 .target = .{
671 .cpu_arch = .s390x,
672 .os_tag = .linux,
673 .abi = .musl,
674 },
675 .link_libc = true,
676 },
677 // Currently hangs in qemu-s390x.
678 // .{
679 // .target = .{
680 // .cpu_arch = .s390x,
681 // .os_tag = .linux,
682 // .abi = .musl,
683 // },
684 // .linkage = .dynamic,
685 // .link_libc = true,
686 // .extra_target = true,
687 // },
688 .{
689 .target = .{
690 .cpu_arch = .s390x,
691 .os_tag = .linux,
692 .abi = .gnu,
693 },
694 .link_libc = true,
695 },
696
697 .{
698 .target = .{
699 .cpu_arch = .sparc64,
700 .os_tag = .linux,
701 .abi = .none,
702 },
703 },
704 // SPARC linking support is currently incomplete.
705 // .{
706 // .target = .{
707 // .cpu_arch = .sparc64,
708 // .os_tag = .linux,
709 // .abi = .gnu,
710 // },
711 // .link_libc = true,
712 // },
713
714 .{
715 .target = .{
716 .cpu_arch = .x86,
717 .os_tag = .linux,
718 .abi = .none,
719 },
720 },
721 .{
722 .target = .{
723 .cpu_arch = .x86,
724 .os_tag = .linux,
725 .abi = .musl,
726 },
727 .link_libc = true,
728 },
729 .{
730 .target = .{
731 .cpu_arch = .x86,
732 .os_tag = .linux,
733 .abi = .musl,
734 },
735 .linkage = .dynamic,
736 .link_libc = true,
737 .extra_target = true,
738 },
739 .{
740 .target = .{
741 .cpu_arch = .x86,
742 .os_tag = .linux,
743 .abi = .gnu,
744 },
745 .link_libc = true,
746 },
747
748 .{
749 .target = .{
750 .cpu_arch = .x86_64,
751 .os_tag = .linux,
752 .abi = .none,
753 },
754 },
755 .{
756 .target = .{
757 .cpu_arch = .x86_64,
758 .os_tag = .linux,
759 .abi = .none,
760 },
761 .use_llvm = true,
762 .use_lld = true,
763 },
764 .{
765 .target = .{
766 .cpu_arch = .x86_64,
767 .os_tag = .linux,
768 .abi = .x32,
769 },
770 },
771 .{
772 .target = .{
773 .cpu_arch = .x86_64,
774 .os_tag = .linux,
775 .abi = .musl,
776 },
777 .link_libc = true,
778 },
779 .{
780 .target = .{
781 .cpu_arch = .x86_64,
782 .os_tag = .linux,
783 .abi = .musl,
784 },
785 .linkage = .dynamic,
786 .link_libc = true,
787 .extra_target = true,
788 },
789 .{
790 .target = .{
791 .cpu_arch = .x86_64,
792 .os_tag = .linux,
793 .abi = .musl,
794 },
795 .link_libc = true,
796 .use_llvm = true,
797 .use_lld = false,
798 },
799 .{
800 .target = .{
801 .cpu_arch = .x86_64,
802 .os_tag = .linux,
803 .abi = .muslx32,
804 },
805 .link_libc = true,
806 },
807 .{
808 .target = .{
809 .cpu_arch = .x86_64,
810 .os_tag = .linux,
811 .abi = .muslx32,
812 },
813 .linkage = .dynamic,
814 .link_libc = true,
815 .extra_target = true,
816 },
817 .{
818 .target = .{
819 .cpu_arch = .x86_64,
820 .os_tag = .linux,
821 .abi = .gnu,
822 },
823 .link_libc = true,
824 },
825 .{
826 .target = .{
827 .cpu_arch = .x86_64,
828 .os_tag = .linux,
829 .abi = .gnux32,
830 },
831 .link_libc = true,
832 },
833
834 // NetBSD Targets
835
836 .{
837 .target = .{
838 .cpu_arch = .riscv32,
839 .os_tag = .netbsd,
840 .abi = .none,
841 },
842 },
843
844 .{
845 .target = .{
846 .cpu_arch = .x86,
847 .os_tag = .netbsd,
848 .abi = .none,
849 },
850 },
851
852 // Windows Targets
853
854 .{
855 .target = .{
856 .cpu_arch = .aarch64,
857 .os_tag = .windows,
858 .abi = .msvc,
859 },
860 },
861 .{
862 .target = .{
863 .cpu_arch = .aarch64,
864 .os_tag = .windows,
865 .abi = .msvc,
866 },
867 .link_libc = true,
868 },
869 .{
870 .target = .{
871 .cpu_arch = .aarch64,
872 .os_tag = .windows,
873 .abi = .gnu,
874 },
875 },
876 .{
877 .target = .{
878 .cpu_arch = .aarch64,
879 .os_tag = .windows,
880 .abi = .gnu,
881 },
882 .link_libc = true,
883 },
884
885 .{
886 .target = .{
887 .cpu_arch = .thumb,
888 .os_tag = .windows,
889 .abi = .msvc,
890 },
891 },
892 .{
893 .target = .{
894 .cpu_arch = .thumb,
895 .os_tag = .windows,
896 .abi = .msvc,
897 },
898 .link_libc = true,
899 },
900 .{
901 .target = .{
902 .cpu_arch = .thumb,
903 .os_tag = .windows,
904 .abi = .gnu,
905 },
906 },
907 .{
908 .target = .{
909 .cpu_arch = .thumb,
910 .os_tag = .windows,
911 .abi = .gnu,
912 },
913 .link_libc = true,
914 },
915
916 .{
917 .target = .{
918 .cpu_arch = .x86,
919 .os_tag = .windows,
920 .abi = .msvc,
921 },
922 },
923 .{
924 .target = .{
925 .cpu_arch = .x86,
926 .os_tag = .windows,
927 .abi = .msvc,
928 },
929 .link_libc = true,
930 },
931 .{
932 .target = .{
933 .cpu_arch = .x86,
934 .os_tag = .windows,
935 .abi = .gnu,
936 },
937 },
938 .{
939 .target = .{
940 .cpu_arch = .x86,
941 .os_tag = .windows,
942 .abi = .gnu,
943 },
944 .link_libc = true,
945 },
946
947 .{
948 .target = .{
949 .cpu_arch = .x86_64,
950 .os_tag = .windows,
951 .abi = .msvc,
952 },
953 },
954 .{
955 .target = .{
956 .cpu_arch = .x86_64,
957 .os_tag = .windows,
958 .abi = .msvc,
959 },
960 .link_libc = true,
961 },
962 .{
963 .target = .{
964 .cpu_arch = .x86_64,
965 .os_tag = .windows,
966 .abi = .gnu,
967 },
968 },
969 .{
970 .target = .{
971 .cpu_arch = .x86_64,
972 .os_tag = .windows,
973 .abi = .gnu,
974 },
975 .link_libc = true,
976 },
977};
978
979const Config = struct {
980 params: *const CaseParameters,
981 target: *const std.Target,
982 name: []const u8,
983 source: []const u8,
984 /// Whether this test case expects to have unwind tables / frame pointers.
985 unwind: enum {
986 /// This case assumes that some unwind strategy, safe or unsafe, is available.
987 any,
988 /// This case assumes that no unwinding strategy is available.
989 none,
990 /// This case assumes that a safe unwind strategy, like DWARF unwinding, is available.
991 safe,
992 /// This case assumes that at most, unsafe FP unwinding is available.
993 no_safe,
994 },
995 /// If `true`, the expected exit code is that of the default panic handler, rather than 0.
996 expect_panic: bool,
997 /// When debug info is not stripped, stdout is expected to **contain** (not equal!) this string.
998 expect: []const u8,
999 /// When debug info *is* stripped, stdout is expected to **contain** (not equal!) this string.
1000 expect_strip: []const u8,
1001};
1002
1003pub fn addCases(self: *StackTrace) void {
1004 const b = self.b;
1005
1006 for (&param_sets) |*params| {
1007 const resolved_target = b.resolveTargetQuery(params.target);
1008 const target = &resolved_target.result;
1009
1010 if (!self.options.test_extra_targets and params.extra_target) continue;
1011
1012 if (self.options.skip_non_native and !tests.isNative(&resolved_target, &b.graph.host.result)) continue;
1013
1014 if (self.options.skip_freebsd and target.os.tag == .freebsd) continue;
1015 if (self.options.skip_netbsd and target.os.tag == .netbsd) continue;
1016 if (self.options.skip_openbsd and target.os.tag == .openbsd) continue;
1017 if (self.options.skip_windows and target.os.tag == .windows) continue;
1018 if (self.options.skip_darwin and target.os.tag.isDarwin()) continue;
1019 if (self.options.skip_linux and target.os.tag == .linux) continue;
1020
1021 const would_use_llvm = tests.wouldUseLlvm(params.use_llvm, params.target, params.optimize);
1022 if (self.options.skip_llvm and would_use_llvm) continue;
1023
1024 const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
1025
1026 if (self.options.test_target_filters.len > 0) {
1027 for (self.options.test_target_filters) |filter| {
1028 if (std.mem.find(u8, triple_txt, filter) != null) break;
1029 } else continue;
1030 }
1031
1032 if (self.options.skip_libc and (params.link_libc == true or std.os.targetRequiresLibC(target)))
1033 continue;
1034
1035 // We can't provide MSVC libc when cross-compiling.
1036 if (target.abi == .msvc and params.link_libc == true and builtin.os.tag != .windows)
1037 continue;
1038
1039 for (self.options.optimize_modes) |optimize| {
1040 if (optimize == params.optimize) break;
1041 } else return;
1042
1043 stack_traces_cases.addCases(self, params, &resolved_target.result);
1044 }
1045}
1046
1047/// Called from test/stack_traces.zig
1048pub fn addCase(self: *StackTrace, config: Config) void {
1049 const params = config.params;
1050 const target = config.target;
1051 const target_query = config.params.target;
1052
1053 const triple: ?[]const u8 = if (target_query.isNative()) null else t: {
1054 break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM");
1055 };
1056
1057 // See `std.debug.StackIterator.fp_usability` logic.
1058 const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.cpu.arch) {
1059 .alpha,
1060 .csky,
1061 .microblaze,
1062 .microblazeel,
1063 .mips,
1064 .mipsel,
1065 .mips64,
1066 .mips64el,
1067 .sh,
1068 .sheb,
1069 .xtensa,
1070 .xtensaeb,
1071 => .useless,
1072 .hexagon,
1073 .powerpc,
1074 .powerpcle,
1075 .powerpc64,
1076 .powerpc64le,
1077 .sparc,
1078 .sparc64,
1079 => .ideal,
1080 .aarch64 => if (target.os.tag.isDarwin()) .safe else .unsafe,
1081 else => .unsafe,
1082 };
1083 const supports_unwind_tables = switch (target.os.tag) {
1084 // x86-windows just has no way to do stack unwinding other than using frame pointers.
1085 .windows => target.cpu.arch != .x86,
1086 else => true,
1087 };
1088
1089 const UnwindInfo = packed struct(u2) {
1090 tables: bool,
1091 fp: bool,
1092 const none: @This() = .{ .tables = false, .fp = false };
1093 const both: @This() = .{ .tables = true, .fp = true };
1094 const only_tables: @This() = .{ .tables = true, .fp = false };
1095 const only_fp: @This() = .{ .tables = false, .fp = true };
1096 };
1097 const unwind_info_vals: []const UnwindInfo = switch (config.unwind) {
1098 .none => switch (fp_usability) {
1099 .useless => &.{ .none, .only_fp },
1100 .unsafe, .safe => &.{.none},
1101 .ideal => &.{},
1102 },
1103 .any => switch (fp_usability) {
1104 .useless => &.{ .only_tables, .both },
1105 .unsafe, .safe, .ideal => &.{ .only_tables, .only_fp, .both },
1106 },
1107 .safe => switch (fp_usability) {
1108 .useless, .unsafe => &.{ .only_tables, .both },
1109 .safe, .ideal => &.{ .only_tables, .only_fp, .both },
1110 },
1111 .no_safe => switch (fp_usability) {
1112 .useless, .unsafe => &.{ .none, .only_fp },
1113 .safe => &.{.none},
1114 .ideal => &.{},
1115 },
1116 };
1117
1118 for (unwind_info_vals) |unwind_info| {
1119 if (unwind_info.tables and !supports_unwind_tables) continue;
1120 const strip = params.strip orelse switch (params.optimize) {
1121 .debug, .fast, .safe => false,
1122 .small => true,
1123 };
1124 self.addCaseInstance(
1125 .{ .result = target.*, .query = target_query },
1126 triple,
1127 config.name,
1128 config.source,
1129 params,
1130 !unwind_info.tables and supports_unwind_tables,
1131 !unwind_info.fp,
1132 config.expect_panic,
1133 if (strip) config.expect_strip else config.expect,
1134 );
1135 }
1136}
1137
1138fn addCaseInstance(
1139 self: *StackTrace,
1140 resolved_target: std.Build.ResolvedTarget,
1141 triple: ?[]const u8,
1142 name: []const u8,
1143 source: []const u8,
1144 params: *const CaseParameters,
1145 strip_unwind: bool,
1146 omit_frame_pointer: bool,
1147 expect_panic: bool,
1148 expect_stderr: []const u8,
1149) void {
1150 const b = self.b;
1151
1152 if (strip_unwind) {
1153 // To enable this coverage, `std.Build.Step.ObjCopy` needs to be un-regressed and gain the
1154 // ability to remove individual sections. `-fno-unwind-tables` is insufficient because it
1155 // does not prevent `.debug_frame` from being emitted. If we could, we would remove the
1156 // following sections:
1157 // * `.eh_frame`, `.eh_frame_hdr`, `.debug_frame` (Linux)
1158 // * `__TEXT,__eh_frame`, `__TEXT,__unwind_info` (macOS)
1159 return;
1160 }
1161
1162 const backend_string = if (params.use_llvm == true)
1163 " llvm"
1164 else if (params.use_llvm == false)
1165 " selfhosted"
1166 else
1167 "";
1168
1169 const strip_string = if (params.strip == true)
1170 " strip"
1171 else if (params.strip == false)
1172 " unstripped"
1173 else
1174 "";
1175
1176 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s}{s})", .{
1177 name,
1178 triple orelse "",
1179 if (triple != null) " " else "",
1180 backend_string,
1181 if (params.pie == true) " pie" else "",
1182 if (params.link_libc == true) " libc" else "",
1183 if (params.linkage) |linkage| switch (linkage) {
1184 inline else => |t| " " ++ @tagName(t),
1185 } else "",
1186 strip_string,
1187 if (strip_unwind) " no_unwind" else "",
1188 if (omit_frame_pointer) " no_fp" else "",
1189 });
1190 if (self.options.test_filters.len > 0) {
1191 for (self.options.test_filters) |test_filter| {
1192 if (mem.find(u8, annotated_case_name, test_filter)) |_| break;
1193 } else return;
1194 }
1195
1196 const write_files = b.addWriteFiles();
1197 const source_zig = write_files.add("source.zig", source);
1198 const exe = b.addExecutable(.{
1199 .name = "test",
1200 .root_module = b.createModule(.{
1201 .root_source_file = source_zig,
1202 .optimize = params.optimize,
1203 .target = resolved_target,
1204 .omit_frame_pointer = omit_frame_pointer,
1205 .link_libc = params.link_libc,
1206 .unwind_tables = if (strip_unwind) .none else null,
1207 // make panics single-threaded so that they don't include a thread ID
1208 .single_threaded = expect_panic,
1209 }),
1210 .use_llvm = params.use_llvm,
1211 .use_lld = params.use_lld,
1212 });
1213 exe.linkage = params.linkage;
1214 exe.pie = params.pie;
1215 exe.bundle_ubsan_rt = false;
1216
1217 const run = b.addRunArtifact(exe);
1218 run.skip_foreign_checks = true;
1219 run.removeEnvironmentVariable("CLICOLOR_FORCE");
1220 run.setEnvironmentVariable("NO_COLOR", "1");
1221 run.addCheck(.{
1222 .expect_term = term: {
1223 if (!expect_panic) break :term .{ .exited = 0 };
1224 if (resolved_target.result.os.tag == .windows) break :term .{ .exited = 3 };
1225 break :term .{ .signal = @fromBackingInt(@intCast(6)) }; // SIGABRT
1226 },
1227 });
1228 run.expectStdOutEqual("");
1229
1230 const check_run = b.addRunArtifact(self.convert_exe);
1231 check_run.setName(annotated_case_name);
1232 check_run.addFileArg(run.captureStdErr(.{}));
1233 check_run.expectExitCode(0);
1234 check_run.addCheck(.{ .expect_stdout_match = expect_stderr });
1235
1236 self.step.dependOn(&check_run.step);
1237}