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