169 lines · python
1#!/usr/bin/env python2 3"""Generate skeletal functions with a variety .cfi_ directives.4The purpose is to produce object-file test inputs to lld with a5variety of compact unwind encodings.6"""7from __future__ import print_function8import random9import argparse10import string11from math import factorial12from itertools import permutations13 14lsda_n = 015lsda_odds = 0.016func_size_low = 0x1017func_size_high = 0x10018saved_regs = ["%r15", "%r14", "%r13", "%r12", "%rbx"]19saved_regs_combined = list(list(permutations(saved_regs, i)) for i in range(0, 6))20 21 22def print_function(name):23 global lsda_odds24 have_lsda = random.random() < lsda_odds25 frame_size = random.randint(4, 64) * 1626 frame_offset = -random.randint(0, int(frame_size / 16 - 4)) * 1627 global func_size_low, func_size_high28 func_size = random.randint(func_size_low, func_size_high) * 0x1029 func_size_high += 130 if func_size_high % 0x10 == 0:31 func_size_low += 132 33 print(34 """\35### %s frame=%d lsda=%s size=%d36 .section __TEXT,__text,regular,pure_instructions37 .p2align 4, 0x9038 .globl %s39%s:40 .cfi_startproc"""41 % (name, frame_size, have_lsda, func_size, name, name)42 )43 if have_lsda:44 global lsda_n45 lsda_n += 146 print(47 """\48 .cfi_personality 155, ___gxx_personality_v049 .cfi_lsda 16, Lexception%d"""50 % lsda_n51 )52 print(53 """\54 pushq %%rbp55 .cfi_def_cfa_offset %d56 .cfi_offset %%rbp, %d57 movq %%rsp, %%rbp58 .cfi_def_cfa_register %%rbp"""59 % (frame_size, frame_offset + 6 * 8)60 )61 print(62 """\63 .fill %d64 popq %%rbp65 retq66 .cfi_endproc67"""68 % (func_size - 6)69 )70 71 if have_lsda:72 print(73 """\74 .section __TEXT,__gcc_except_tab75 .p2align 276Lexception%d:77 .space 0x1078"""79 % lsda_n80 )81 return func_size82 83 84def random_seed():85 """Generate a seed that can easily be passed back in via --seed=STRING"""86 return "".join(random.choice(string.ascii_lowercase) for i in range(10))87 88 89def main():90 parser = argparse.ArgumentParser(91 description=__doc__,92 epilog="""\93Function sizes begin small then monotonically increase. The goal is94to produce early pages that are full and later pages that are less95than full, in order to test handling for both cases. Full pages96contain the maximum of 1021 compact unwind entries for a total page97size = 4 KiB.98 99Use --pages=N or --functions=N to control the size of the output.100Default is --pages=2, meaning produce at least two full pages of101compact unwind entries, plus some more. The calculation is sloppy.102""",103 )104 parser.add_argument(105 "--seed",106 type=str,107 default=random_seed(),108 help="Seed the random number generator",109 )110 parser.add_argument(111 "--pages", type=int, default=2, help="Number of compact-unwind pages"112 )113 parser.add_argument(114 "--functions", type=int, default=None, help="Number of functions to generate"115 )116 parser.add_argument(117 "--encodings",118 type=int,119 default=127,120 help="Maximum number of unique unwind encodings (default = 127)",121 )122 parser.add_argument(123 "--lsda",124 type=int,125 default=0,126 help="Percentage of functions with personality & LSDA (default = 10",127 )128 args = parser.parse_args()129 random.seed(args.seed)130 p2align = 14131 global lsda_odds132 lsda_odds = args.lsda / 100.0133 134 print(135 """\136### seed=%s lsda=%f p2align=%d137 .section __TEXT,__text,regular,pure_instructions138 .p2align %d, 0x90139"""140 % (args.seed, lsda_odds, p2align, p2align)141 )142 143 size = 0144 base = 1 << p2align145 if args.functions:146 for n in range(args.functions):147 size += print_function("x%08x" % (size + base))148 else:149 while size < (args.pages << 24):150 size += print_function("x%08x" % (size + base))151 152 print(153 """\154 .section __TEXT,__text,regular,pure_instructions155 .globl _main156 .p2align 4, 0x90157_main:158 retq159 160 .p2align 4, 0x90161___gxx_personality_v0:162 retq163"""164 )165 166 167if __name__ == "__main__":168 main()169